πŸ“š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 ⏱ 10 minutes K8s 1.28+

Disable OperatorHub Default Sources

Disable default OperatorHub catalog sources in OpenShift for air-gapped clusters. Use OperatorHub CR to disable individual or all sources with Ansible auto.

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

πŸ’‘ Quick Answer: Set spec.disableAllDefaultSources: true on the OperatorHub CR named cluster to disable all default catalog sources in an air-gapped OpenShift cluster. For selective disabling, use spec.sources[] with disabled: true per source.

The Problem

OpenShift ships with four default OperatorHub catalog sources that require internet access:

  • redhat-operators β€” Red Hat certified operators
  • certified-operators β€” ISV certified operators
  • community-operators β€” Community-maintained operators
  • redhat-marketplace β€” Red Hat Marketplace operators

In air-gapped (disconnected) clusters, these sources:

  • Generate constant failed pull attempts against registry.redhat.io
  • Produce noisy error logs in the openshift-marketplace namespace
  • Consume cluster resources attempting to sync unreachable catalogs
  • Must be replaced with mirrored catalog sources from a local registry

The Solution

Disable All Sources at Once

apiVersion: config.openshift.io/v1
kind: OperatorHub
metadata:
  name: cluster
spec:
  disableAllDefaultSources: true
oc apply -f - <<EOF
apiVersion: config.openshift.io/v1
kind: OperatorHub
metadata:
  name: cluster
spec:
  disableAllDefaultSources: true
EOF

Disable Individual Sources

apiVersion: config.openshift.io/v1
kind: OperatorHub
metadata:
  name: cluster
spec:
  sources:
    - name: redhat-operators
      disabled: true
    - name: certified-operators
      disabled: true
    - name: community-operators
      disabled: true
    - name: redhat-marketplace
      disabled: true

Ansible Automation

---
- name: Manage OperatorHub default sources
  hosts: localhost
  vars:
    kubeconfig_path: "{{ lookup('env', 'KUBECONFIG') | default('~/.kube/config') }}"
    disable_default_operatorhub_sources: true
    operatorhub_disable_all: false

  tasks:
    - name: Disable specific default OperatorHub sources
      when: disable_default_operatorhub_sources and not operatorhub_disable_all
      kubernetes.core.k8s:
        kubeconfig: "{{ kubeconfig_path }}"
        state: present
        definition:
          apiVersion: config.openshift.io/v1
          kind: OperatorHub
          metadata:
            name: cluster
          spec:
            sources:
              - { name: redhat-operators, disabled: true }
              - { name: certified-operators, disabled: true }
              - { name: community-operators, disabled: true }
              - { name: redhat-marketplace, disabled: true }

    - name: Disable all default OperatorHub sources at once
      when: disable_default_operatorhub_sources and operatorhub_disable_all
      kubernetes.core.k8s:
        kubeconfig: "{{ kubeconfig_path }}"
        state: present
        definition:
          apiVersion: config.openshift.io/v1
          kind: OperatorHub
          metadata:
            name: cluster
          spec:
            disableAllDefaultSources: true

    - name: Re-enable default OperatorHub sources
      when: not disable_default_operatorhub_sources
      kubernetes.core.k8s:
        kubeconfig: "{{ kubeconfig_path }}"
        state: present
        definition:
          apiVersion: config.openshift.io/v1
          kind: OperatorHub
          metadata:
            name: cluster
          spec:
            disableAllDefaultSources: false
            sources: []

Add Mirrored Catalog Source

After disabling defaults, add your local mirror:

apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
  name: custom-operators
  namespace: openshift-marketplace
spec:
  sourceType: grpc
  image: registry.example.com:5000/olm/redhat-operator-index:v4.15
  displayName: Custom Operator Catalog
  publisher: Internal
  updateStrategy:
    registryPoll:
      interval: 30m

Verify

# Check OperatorHub status
oc get operatorhub cluster -o yaml

# Verify catalog sources
oc get catalogsource -n openshift-marketplace

# Check marketplace pods (should only show custom sources)
oc get pods -n openshift-marketplace

# Verify no failed pulls
oc get events -n openshift-marketplace --field-selector reason=Failed
graph TD
    subgraph Default Sources Disabled
        OH[OperatorHub CR<br/>name: cluster] -->|disableAllDefaultSources: true| NONE[No Default Catalogs]
    end
    
    subgraph Custom Mirror
        CS[CatalogSource<br/>custom-operators] --> REG[Local Registry<br/>registry.example.com:5000]
        REG --> IDX[Operator Index Image]
    end
    
    subgraph Before
        RH[redhat-operators ❌]
        CERT[certified-operators ❌]
        COMM[community-operators ❌]
        MKT[redhat-marketplace ❌]
    end
    
    OH --> CS

Common Issues

Catalog pods still running after disabling

OLM may take a few minutes to reconcile. Force deletion:

oc delete pods -n openshift-marketplace -l olm.catalogSource=redhat-operators

disableAllDefaultSources vs sources[]

  • disableAllDefaultSources: true β€” blanket disable, simplest for fully air-gapped
  • sources[] with disabled: true β€” selective, allows keeping some defaults enabled
  • Both can’t be used simultaneously β€” disableAllDefaultSources takes precedence

Custom CatalogSource image pull fails

Ensure the mirrored index image is accessible and the pull secret includes credentials for your local registry:

oc get secret pull-secret -n openshift-config -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jq

Ansible kubernetes.core.k8s module not found

Install the collection:

ansible-galaxy collection install kubernetes.core
pip install kubernetes

Best Practices

  • Use disableAllDefaultSources: true for fully air-gapped clusters β€” cleaner than listing each source
  • Mirror catalogs before disabling β€” ensure operators are available from your local registry
  • Use oc-mirror CLI to mirror operator catalogs to your local registry
  • Set updateStrategy.registryPoll.interval to control how often OLM checks for catalog updates
  • Automate with Ansible for consistent Day 2 operations across multiple clusters
  • Verify with oc get catalogsource after changes β€” ensure only intended sources are active

Key Takeaways

  • OpenShift’s OperatorHub CR (named cluster) controls default catalog sources
  • disableAllDefaultSources: true is the fastest way to silence internet-dependent catalogs
  • spec.sources[] allows selective disabling of individual catalogs
  • Air-gapped clusters must replace defaults with mirrored CatalogSource CRs
  • The kubernetes.core.k8s Ansible module provides declarative, idempotent management
  • Always add your mirrored catalog source before disabling defaults to avoid operator gaps
#openshift #operatorhub #air-gapped #disconnected #ansible #catalog-sources
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