OpenShift 4.20+: Architecture Design Workshop Interactive

Capture every decision for a customer deployment in one place. Export as JSON for the runbook or installer inputs.

OpenShift 4.20+ Architecture Design Workshop

Capture every decision for a customer deployment in one place. Everything you type is saved to your browser's localStorage and can be exported as JSON for the runbook or installer inputs. Use the cluster tabs below to design multiple clusters (e.g. management + hosted, prod + DR).

1. Cluster & Network

Full cluster domain = <name>.<base>

Network CIDRs

External / Physical Network Machine Network (e.g. 10.0.0.0/24) Physical NIC IPs of every node β€” the only network your infrastructure team provisions. Nodes, VIPs, LB, DNS all live here. Master Node (10.0.0.11) Worker Node (10.0.0.21) Worker Node (10.0.0.22) Cluster Network (Pods) 10.128.0.0/23 slice Pod A Pod B Cluster Network (Pods) 10.128.2.0/23 slice Pod C Pod D Cluster Network (Pods) 10.128.4.0/23 slice Pod E Pod F Service Network 172.30.0.0/16 (virtual) Service Network 172.30.0.0/16 (virtual) Service Network 172.30.0.0/16 (virtual) OVN-Kubernetes overlay (Geneve tunnels) connects pods & services across nodes EgressIP Range (e.g. 10.0.0.200–220) Reserved from Machine Network β€” SNAT for outbound pod traffic Pods β†’ EgressIP β†’ External destination (stable source IP) SNAT MetalLB Pool (e.g. 10.0.0.230–250) Reserved from Machine Network β€” LoadBalancer Service IPs External client β†’ MetalLB VIP β†’ Service β†’ Pod (L2/BGP) LB svc Machine Network β€” real IPs, infra-provisioned Cluster Network β€” pod IPs, per-node slice Service Network β€” virtual ClusterIPs EgressIP β€” stable outbound SNAT from Machine Network MetalLB β€” LoadBalancer VIPs from Machine Network
Machine Network is the only network your infrastructure team provisions (physical/VLAN). Cluster Network and Service Network are virtual overlays managed by OpenShift. EgressIP and MetalLB ranges are reserved from the Machine Network β€” they must not overlap with node IPs, VIPs, DHCP, or each other.
Subnet of node NICs
Default 10.128.0.0/14
/23 β‡’ 510 pod IPs/node
Default 250 β€” kubelet maxPods limit; constrained by Host Prefix IP capacity
Geneve overhead ~100 bytes
MTU in mixed environments (VM + Bare Metal): All nodes must have the same MTU on their primary interface β€” control-plane VMs and bare-metal workers alike. OVN-Kubernetes auto-detects the lowest MTU across nodes; a mismatch causes silent packet drops.

Jumbo frames (9000) checklist:
  • vSwitch / Distributed vSwitch on ESXi hosts → MTU 9000
  • VM port group carrying OCP traffic → MTU 9000
  • Every physical switch & router between VM hosts and bare-metal workers → MTU 9000
  • Bare-metal NIC, bond, and VLAN interfaces → MTU 9000 (see NMState section below)
Overlay overhead: OVN Geneve subtracts 100 bytes → set cluster network MTU to physical MTU − 100 (e.g., 9000 → 8900). With IPsec, subtract an additional 46 bytes.
Best practice: If end-to-end jumbo frame support cannot be confirmed across all links, use MTU 1500 (overlay 1400).
Post-install change is disruptive: MTU migration after install triggers two rolling reboots of all nodes — plan MTU at install time.

Reserved IP Ranges (from Machine Network)

These ranges are carved out of the Machine Network and must not overlap with node IPs, VIPs, or each other. Document them here so the network team can reserve them.
IPs assigned to EgressIP CRs for SNAT β€” must be routable from Machine Network, not used by nodes or DHCP
IPs for LoadBalancer Services (L2 or BGP mode) β€” must not overlap with node IPs or EgressIP range
Reserved / conflicting CIDRs β€” do NOT use these for Cluster or Service networks:
CIDRReason
10.88.0.0/16Default Podman / CNI bridge network on RHCOS. Podman uses this for rootless container networking on nodes β€” overlapping will break host-level container operations and machine-config-daemon pivot.
100.64.0.0/16Reserved by OVN-Kubernetes for internal transit switch (join subnet). Using it causes routing conflicts and pod connectivity failures.
100.88.0.0/16Reserved by OVN-Kubernetes for internal masquerade / gateway operations (egress SNAT). Configurable via v4InternalMasqueradeSubnet but defaults to this range.
169.254.0.0/16Link-local range (RFC 3927). Used by cloud metadata services and APIPA β€” will collide with node-level networking.
224.0.0.0/4Multicast range β€” not routable for unicast pod traffic.
255.255.255.255/32Broadcast address.

Also avoid overlap with your Machine Network, corporate VPNs, on-prem data-center ranges, or any network reachable via the node's default gateway. The installer does not validate against external routing β€” only against internal overlap between Cluster, Service, and Machine CIDRs.

VIPs, DNS, NTP

api.<cluster>.<base>
*.apps.<cluster>.<base>
Must resolve api, api-int, *.apps

Proxy Configuration

The installer auto-adds node, pod, and service CIDRs
Required proxy allowlist for OpenShift installation

If the cluster goes through a forward proxy, the following destinations must be allowed (HTTPS/443 unless noted). Block any of these and the install or day-2 operations will fail silently or hang.

DestinationPurpose
quay.ioPrimary container image registry for OpenShift release and operator images
cdn.quay.ioCDN layer for Quay β€” serves image blobs
cdn01.quay.io β€” cdn03.quay.ioAdditional Quay CDN endpoints (may expand over time)
registry.redhat.ioRed Hat certified operator and container images
registry.access.redhat.comLegacy Red Hat container image registry (still referenced by some images)
access.redhat.comRed Hat Errata and content (signature verification)
sso.redhat.comRed Hat SSO β€” token auth for registry pulls and console.redhat.com
console.redhat.comTelemetry, Insights, Assisted Installer, cluster registration
api.openshift.comCluster registration, subscription management
mirror.openshift.comOpenShift release mirror (installer, oc client, RHCOS images)
storage.googleapis.com/openshift-releaseGCS-hosted release image signatures
quayio-production-s3.s3.amazonaws.comS3 backend for Quay image layers
rhcos.mirror.openshift.comRHCOS ISO and rootfs images for node provisioning
cert-api.access.redhat.comInsights certificate-based authentication
infogw.api.openshift.comInsights data upload gateway
cloud.redhat.comInsights / Telemetry (legacy endpoint, still in use)
no_proxy auto-populated by installer: .cluster.local, .svc, localhost, 127.0.0.1, API VIP, Ingress VIP, Machine CIDR, Pod CIDR, Service CIDR. Add any internal registries, Git repos, artifact stores, or corporate services that must bypass the proxy.
Air-gapped / disconnected installs: If you cannot allow-list the above, you must mirror all content to a local registry using oc mirror or oc adm release mirror. The proxy section becomes N/A β€” instead, configure ImageDigestMirrorSet / ImageTagMirrorSet CRs (OCP 4.14+; the older imageContentSources field is deprecated).

Load Balancer

External = you manage a separate LB appliance/VM. Built-in = OpenShift deploys HAProxy & Keepalived on nodes (IPI/ABI default).
Auto-filled from API VIP
Auto-filled from API VIP
Auto-filled from Ingress VIP

API & Machine Config Server

*.apps Ingress (Routes) β€” targets workers with router pods

Diagrams auto-update from the node table below. Nodes with Role containing master appear in the API diagram. *.apps traffic goes only to nodes with the Router checkbox enabled. When Role = master/worker, both diagrams combine into one. By default, router pods run as a DaemonSet on all workers β€” restrict with IngressController.spec.nodePlacement.

Nodes (Hardware, IP, VLAN, FQDN)

#RoleHostname (FQDN)CPURAMDiskRAIDIPSubnet MaskVLANGatewayRouterOCP NodeDNS

Required DNS Records

All records below must resolve before installation begins. The installer validates DNS as a preflight check. Records auto-populate from cluster name, base domain, VIPs, and node entries above.
Record (FQDN)TypeTargetPurpose
Wildcard DNS: The *.apps record must be a true wildcard A record, not a CNAME. Some DNS providers (e.g. certain Windows DNS or split-horizon setups) handle wildcards differently β€” test with dig test123.apps.<cluster>.<base> before install.

Firewall Rules

Rules auto-populate from cluster, VIP, node, DNS, NTP, proxy, and SMTP fields above. Share this table with the network/security team before installation. Direction is source β†’ destination.
How to represent OCP node sources in firewall rules
Source IP that control plane nodes see from the API load balancer
Source IP that router nodes see from the Ingress load balancer
Category Source Destination Port(s) Description

2. Platform & Installer

ABI = air-gapped; Assisted = SaaS
NMState / MachineConfig bond interface name

Node BMC Addresses

#HostnameBMC Address
Never store BMC passwords in this file. Use a secret manager (Vault / Sealed Secrets) and reference them in install-config.yaml via the bmc.password field at install time.

Port Mapping (NICs / Switch Ports)

Network interface stack per bare-metal host: physical NICs are bonded, then VLANs are tagged on the bond with IP addresses assigned. Each row is one interface β€” add multiple rows per host to build the full stack.

# Hostname Interface Type MAC Address Bond / Parent Switch Port VLAN ID MTU IP / Prefix Gateway Purpose
Tip: For a typical bonded host, add rows in order: 2Γ— ethernet (bond slaves with MACs & switch ports) β†’ 1Γ— bond (bond0, mode 802.3ad) β†’ 1Γ— vlan (bond0.100 with IP). Use "Preset" to auto-populate this pattern.

3. Monitoring β€” Prometheus

Default retention: 15 days. Runs 2 replicas in openshift-monitoring. Formula: disk β‰ˆ retention_s Γ— samples/s Γ— bytes/sample.

OpenShift Monitoring Stack β€” Prometheus, Thanos & Alertmanager ⚑ Cluster Monitoring Operator openshift-monitoring Prometheus (Γ—2 HA) TSDB PVC (retention) Thanos Sidecar exposes StoreAPI :10901 Scrapes: kubelet Β· cAdvisor Β· node-exporter Β· kube-state-metrics Β· etcd Thanos Querier unified PromQL endpoint :9091 / :9092 / :9093 StoreAPI Alertmanager (Γ—2 HA) Receivers: Email/SMTP Slack PagerDuty Webhook silence Β· inhibit Β· group Β· route firing alerts Prometheus Adapter custom metrics HPA kube-state-metrics node-exporter (DS) openshift-state-metrics Telemeter Client scrape openshift-user-workload-monitoring Optional Prometheus user metrics Thanos Sidecar StoreAPI StoreAPI Thanos Ruler recording + alerting rules query alerts Scrapes user ServiceMonitor and PodMonitor CRs OCP Console Observe β†’ Metrics / Alerts PromQL Cluster Nodes kubelet Β· cAdvisor metrics Notification Targets SMTP relay Β· Slack Β· PagerDuty Β· webhook User Pods /metrics scrape Platform Prometheus Thanos (Querier / Sidecar) UWM (optional) Alerting path Thanos Querier is the single query endpoint β€” OCP Console and external tools query it, not Prometheus directly. Thanos Sidecar exposes StoreAPI (no object storage upload by default). Thanos Ruler evaluates user alerting/recording rules.
Architecture: The Cluster Monitoring Operator deploys Prometheus (2 HA replicas), Alertmanager, and Thanos Querier in openshift-monitoring. Each Prometheus has a Thanos Sidecar that exposes a StoreAPI β€” Thanos Querier is the unified PromQL endpoint that aggregates data from all sidecars. The OCP Console queries Thanos Querier, not Prometheus directly. Alertmanager receives firing alerts and routes to receivers. When User Workload Monitoring is enabled, a separate Prometheus + Thanos Sidecar + Thanos Ruler is deployed in openshift-user-workload-monitoring. Thanos Ruler evaluates recording and alerting rules for user workloads, querying data via Thanos Querier and sending alerts to Alertmanager.
Sizing parameter reference
ParameterDescription
Retention (days)How long Prometheus keeps TSDB data on disk. Default in OpenShift: 15 days (15d). Longer retention = more disk. Set via prometheusK8s.retention in the cluster-monitoring-config ConfigMap. For long-term storage beyond the retention window, use prometheusK8s.remoteWrite to an external system (Thanos Receive, Mimir, an observability platform) β€” the bundled Thanos sidecar only serves in-cluster queries and cannot be attached to object storage.
Total NodesNumber of nodes in the cluster. Each node runs a node-exporter DaemonSet pod that emits hardware/OS metrics. More nodes = more time series = more disk and memory. Include all roles (master, worker, infra).
Samples/sec per NodeAverage metric samples ingested per second per node. Baseline for cluster-monitoring stack is ~8,000–12,000 samples/sec/node. This includes kubelet, cAdvisor, node-exporter, kube-state-metrics, and etcd metrics. Enabling User Workload Monitoring (UWM) or adding ServiceMonitors increases this number β€” measure with prometheus_tsdb_head_samples_appended_total.
Bytes/SampleAverage on-disk size per sample after TSDB compression. Typical range: 1.5–2 bytes. This is the post-compaction size β€” TSDB blocks compress efficiently. The default 2 bytes is a conservative estimate; low-cardinality clusters may see closer to 1.5.
ReplicasNumber of Prometheus replicas. Default: 2 for HA in openshift-monitoring. Each replica stores a full copy of all metrics independently (no shared storage). Total storage = per-replica size Γ— replicas. Do not reduce below 2 in production β€” you lose HA during rolling updates.
Headroom %Extra buffer on top of the calculated disk size. Accounts for: WAL (Write-Ahead Log) segments (~20% of retention volume), compaction temporary files (TSDB merges blocks in place), series churn from pod restarts and deployments, and growth margin. Default 40% is suitable for most production clusters. Reduce to 20–30% if the cluster is stable with low churn.
Cluster-monitoring baseline: ~8–12k/node
Compressed TSDB β‰ˆ 1.5–2 B
Churn + compaction + WAL
Configure via the cluster-monitoring-config ConfigMap β€” set prometheusK8s.retention and volumeClaimTemplate (PVC).

User Workload Monitoring (UWM)

UWM runs a separate Prometheus in openshift-user-workload-monitoring to scrape user-defined ServiceMonitor and PodMonitor CRs. Sized independently from platform monitoring β€” has its own retention and PVC settings via the user-workload-monitoring-config ConfigMap.

Set enableUserWorkload: true in cluster-monitoring-config
Default 15d β€” set via user-workload-monitoring-config
Depends on number of custom metrics and retention
Default 2 for HA
Enable User Workload Monitoring
# 1. Enable UWM in cluster-monitoring-config
oc -n openshift-monitoring edit configmap cluster-monitoring-config
# Add under data.config.yaml:
#   enableUserWorkload: true

# 2. Configure UWM retention and storage
oc -n openshift-user-workload-monitoring create configmap user-workload-monitoring-config
oc -n openshift-user-workload-monitoring edit configmap user-workload-monitoring-config
# Add under data.config.yaml:
#   prometheus:
#     retention: 15d
#     volumeClaimTemplate:
#       spec:
#         storageClassName: gp3-csi
#         resources:
#           requests:
#             storage: 50Gi

# 3. Verify UWM pods are running
oc get pods -n openshift-user-workload-monitoring

# 4. Create a ServiceMonitor for your app
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: my-app-monitor
  namespace: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  endpoints:
    - port: metrics
      interval: 30s
Resource impact: UWM adds 2 Prometheus pods + 1 Thanos Ruler pod. Each Prometheus replica needs its own PVC. Plan for ~2 vCPU and 6–8 GB RAM per replica as baseline β€” scales with number of custom metrics and scrape targets.

Alertmanager β€” SMTP / Email Notifications

Alertmanager is configured via a Secret named alertmanager-main in openshift-monitoring. SMTP settings go in the global section of the Alertmanager config.

host:port β€” use 587 for STARTTLS (Prometheus Alertmanager does not support implicit TLS on port 465)
Leave blank if relay does not require auth
Never store SMTP passwords in the workshop export. Store them in a Secret and reference via Alertmanager config's smtp_auth_password_file or use a no-auth internal relay.

4. Storage β€” CSI & Protocol

Storage provisioning and CSI drivers are typically outside Red Hat's support scope β€” the storage vendor provides and supports the CSI driver. Document the storage backend here for the implementation runbook.

Support boundary: Red Hat supports the CSI interface and StorageClass API. The CSI driver itself, storage array configuration, zoning, LUN masking, and protocol-level troubleshooting are the storage vendor's responsibility. Ensure the vendor's CSI driver is certified for OpenShift β€” check the Red Hat Ecosystem Catalog.
CSI driver name β€” must be certified for OCP
Design checklist:
  • Multipath: iSCSI / FC / NVMe-oF need multipathd enabled on nodes via a day-1 MachineConfig (and iSCSI initiator config). Plan two independent fabric/network paths.
  • Default StorageClass: exactly one SC should carry storageclass.kubernetes.io/is-default-class: "true" β€” multiple defaults break PVC binding for claims without an explicit class.
  • Capabilities: confirm the CSI driver supports volume expansion (allowVolumeExpansion), snapshots (create a VolumeSnapshotClass), and cloning β€” needed by OpenShift Virtualization and backup tooling (OADP).
  • Access modes: NFS / CephFS = RWX filesystem; iSCSI / FC / RBD block = RWO (RWX only as raw block). Workloads needing shared writable volumes (e.g. some CI, AI training) need an RWX-capable class.

CSI Architecture β€” How Persistent Volumes Are Provisioned

CSI Provisioning Flow User / Workload creates PVC PVC StorageClass ref StorageClass provisioner: csi-driver OpenShift Cluster CSI Controller external-provisioner sidecar external-attacher sidecar Worker Node 1 CSI Node Plugin kubelet mount Worker Node 2 CSI Node Plugin kubelet mount Worker Node N CSI Node Plugin kubelet mount Storage Backend iSCSI / FC / NFS / S3 provision mount

5. Logging β€” Loki (LokiStack)

OCP 4.20 uses Loki via the Cluster Logging Operator (ClusterLogForwarder / LokiStack). Storage is object storage (S3, ODF, Swift, Azure, GCS). Sizing follows the t-shirt size model from Red Hat docs.

⚑ Logging Operator ⚑ Loki Operator ⚑ Cluster Observability Operator ClusterLogForwarder CR LokiStack CR UIPlugin CR Node β€” DaemonSet V ector Vector Grafana Loki OpenShift Console Forwarding External Logging System β€’ Syslog β€’ Elasticsearch β€’ Splunk / SIEM β€’ Kafka Object Storage (S3 / ODF / Azure / GCS) 3 tenants: app / infra / audit
Architecture: The Logging Operator deploys Vector (DaemonSet) on every node to collect container and journal logs. ClusterLogForwarder CR defines pipelines β€” logs flow to the local LokiStack (managed by the Loki Operator) and/or external destinations. Loki stores compressed chunks in object storage. The Cluster Observability Operator installs the UIPlugin CR to enable log viewing in the OpenShift Console.
Sizing parameter reference
ParameterDescription
LokiStack SizeT-shirt size that determines component replica counts, resource requests/limits, and concurrency. Each size has a maximum ingestion rate: 1x.demo ≀100 GB/day (no HA), 1x.pico ≀50 GB/day, 1x.extra-small ≀100 GB/day, 1x.small ≀500 GB/day, 1x.medium ≀2 TB/day.
Compression FactorRatio of compressed chunk size to raw log size. Loki compresses log data into chunks before writing to object storage. Typical values range from 0.06 to 0.20 (i.e. 6–20% of raw size). Lower values mean better compression. The default 0.15 is a safe middle estimate; actual ratio depends on log entropy and repetitiveness.
Replication FactorNumber of ingester replicas that receive each write. In OpenShift Logging 6.x (OCP 4.20+) this is automatically set to 2 for all production sizes and cannot be overridden in the CR:
1x.demo = none (no HA), 1x.pico = 2, 1x.extra-small = 2, 1x.small = 2, 1x.medium = 2.
This controls Loki's internal write replication across ingesters (WAL durability). It does not directly multiply object-store usage β€” object storage has its own replication (e.g. S3 11Γ—9s durability, ODF 3-way replicated pool). Do not double-count: if your object store already replicates, storage sizing uses replication factor = 1.
Headroom %Extra storage buffer beyond the calculated compressed volume. Accounts for:
β€’ Index files β€” TSDB index (labels, series metadata) stored alongside chunks
β€’ Compaction temp space β€” compactor rewrites/merges chunks in-place, needing temporary headroom
β€’ WAL segments β€” Write-Ahead Log on ingester PVCs (~2 GB per ingester by default)
β€’ Chunk overlap β€” during retention enforcement, chunks spanning the boundary are kept until they fully expire
β€’ Growth margin β€” log volume tends to grow as workloads scale
Recommended: 20% for stable clusters, 30–40% for clusters with bursty log patterns or high pod churn.
Retention (per-tenant)How many days of logs to keep, configured separately for each tenant (log type) in OCP 4.20+. OpenShift Loki has three built-in tenants:
β€’ application β€” container logs from user workload namespaces
β€’ infrastructure β€” logs from openshift-*, kube-* namespaces and node journals
β€’ audit β€” Kubernetes API audit logs, OAuth audit, OVN audit

Configured via LokiStack.spec.limits.global.retention (default for all) and LokiStack.spec.limits.tenants.<name>.retention (per-tenant override). Loki's compactor deletes chunks older than retention during its compaction cycle. Typical patterns: keep audit logs longest (compliance), infrastructure medium, application shortest.
application tenant ingest rate
infrastructure tenant ingest rate
audit tenant ingest rate
Loki chunks ~6–20% of raw
Auto-set by LokiStack size
Estimation only: These numbers are rough estimates based on assumed ingest rates and compression ratios. Actual storage depends on log verbosity, application behavior, pod churn, and real-world compression. Use this as a starting point for capacity planning β€” monitor actual usage after deployment and adjust accordingly.
Per-tenant retention is configured in LokiStack.spec.limits.tenants.<name>.retention where name is application, infrastructure, or audit. The replication factor is fixed per LokiStack size and cannot be changed in the CR. Object storage sizing should not be multiplied by the replication factor β€” that controls ingester-level WAL replication, not object-store copies. If your object store has its own replication (ODF replicated pool, S3 durability), storage is already durable.

Log Forwarding Destinations (ClusterLogForwarder)

Use ClusterLogForwarder to send logs to external systems in addition to (or instead of) the local LokiStack. Multiple outputs and pipelines can be defined.

# Output Name Type URL / Endpoint Input Sources
Common output types: lokiStack (default local), elasticsearch, kafka, splunk, syslog, cloudwatch, http (generic webhook). Input sources: application, infrastructure, audit. TLS certs and secrets are referenced in the CR, not stored here.

6. Authentication β€” OAuth Identity Providers

OpenShift uses the built-in OAuth server. Identity providers are configured via the OAuth cluster resource (oc edit oauth cluster). Multiple providers can coexist.

OAuth Authentication Flow Diagram
OpenShift OAuth Authentication Flow User / Browser or oc login OpenShift Cluster OAuth Server openshift-authentication ns Identity Provider LDAP / HTPasswd / OIDC 1. login 2. authenticate 3. identity confirmed OAuth Token access_token 4. issue token API Server validates token 5. bearer token kubeconfig ~/.kube/config saved RBAC ClusterRole / RoleBinding 6. authorize

HTPasswd

Simple file-based auth β€” good for break-glass admin accounts, lab clusters, or bootstrapping before LDAP is ready. The htpasswd file is stored in a Secret in openshift-config.

Shows on the login page
openshift-config namespace
Created with: htpasswd -c -B -b users.htpasswd <user> <pass>
HTPasswd setup commands
# Create the htpasswd file
htpasswd -c -B -b users.htpasswd admin 'CHANGE_ME'
htpasswd -B -b users.htpasswd emergency-admin 'CHANGE_ME'

# Create the secret in openshift-config
oc create secret generic htpasswd-secret \
  --from-file=htpasswd=users.htpasswd \
  -n openshift-config

# Patch the OAuth resource
oc edit oauth cluster
# Add under spec.identityProviders:
#   - name: htpasswd-local
#     type: HTPasswd
#     htpasswd:
#       fileData:
#         name: htpasswd-secret

# Grant cluster-admin to the admin user
oc adm policy add-cluster-role-to-user cluster-admin admin

LDAP / Active Directory

Connects to an external LDAP directory (AD, FreeIPA, OpenLDAP). Users are looked up on each login β€” no sync is needed for authentication, but oc adm groups sync is required for RBAC via group membership.

Shows on the login page
ldap:// or ldaps:// Β· base DN Β· attribute Β· scope Β· filter
Service account for LDAP search (leave blank for anonymous bind)
Secret in openshift-config containing the bind password
ConfigMap in openshift-config with ca.crt (required for ldaps://)

LDAP Attribute Mapping

Unique, stable identifier (default: dn)
AD: sAMAccountName Β· LDAP: uid
Shown in the OCP console

LDAP Group Sync (for RBAC)

Only sync groups matching this filter
CronJob in openshift-authentication or external
LDAP group sync command
# Create a sync config file (ldap-sync.yaml):
kind: LDAPSyncConfig
apiVersion: v1
url: ldaps://ldap.example.com:636
bindDN: cn=ocp-svc,ou=ServiceAccounts,dc=example,dc=com
bindPassword:
  file: /etc/secrets/bindPassword
ca: /etc/ldap-ca/ca.crt
insecure: false
activeDirectory:
  usersQuery:
    baseDN: "dc=example,dc=com"
    scope: sub
    derefAliases: never
    filter: (objectClass=person)
    pageSize: 0
  userNameAttributes: [ sAMAccountName ]
  groupMembershipAttributes: [ memberOf ]

# Run the sync
oc adm groups sync --sync-config=ldap-sync.yaml --confirm

# Bind a synced group to a cluster role
oc adm policy add-cluster-role-to-group cluster-admin ocp-admins
Never store LDAP bind passwords in this workshop export. Use oc create secret generic ldap-bind-password --from-literal=bindPassword='...' -n openshift-config and reference the secret name above.

OpenID Connect (OIDC)

Connects the OAuth server to an OIDC issuer (Microsoft Entra ID, Keycloak / RH-SSO, Okta, PingFederate). Uses the Authorization Code flow β€” the issuer must allow the cluster's redirect URI https://oauth-openshift.apps.<cluster>.<base>/oauth2callback/<provider-name>.

Shows on the login page β€” also part of the redirect URI
Must serve /.well-known/openid-configuration over https
Secret in openshift-config (never the secret value itself)
Entra ID: upn or email Β· Keycloak: preferred_username
Maps IdP groups to OCP groups on each login (no sync job needed)
openshift-config β€” only if the issuer uses a private CA
OIDC identity provider configuration
# Create the client secret in openshift-config
oc create secret generic oidc-client-secret \
  --from-literal=clientSecret='CHANGE_ME' \
  -n openshift-config

# Patch the OAuth resource
oc edit oauth cluster
# Add under spec.identityProviders:
#   - name: entra-id
#     mappingMethod: claim
#     type: OpenID
#     openID:
#       clientID: ocp-cluster-prod
#       clientSecret:
#         name: oidc-client-secret
#       issuer: https://login.microsoftonline.com/<tenant-id>/v2.0
#       claims:
#         preferredUsername: [ preferred_username ]
#         name: [ name ]
#         email: [ email ]
#         groups: [ groups ]
#       extraScopes: [ email, profile ]
New in 4.20 (GA): Instead of the built-in OAuth server, you can enable direct external OIDC authentication β€” the kube-apiserver validates the IdP's tokens natively (upstream structured authentication config, oc gets an oc-oidc plugin with Auth Code + PKCE). Replaces OAuth entirely and can be switched back. Consider it when the customer requires IdP-controlled sessions or one IdP across many clusters. See Authentication β†’ Enabling direct authentication with an external OIDC identity provider.

7. Certificates β€” Ingress, API & Custom CAs

By default, OpenShift generates self-signed certificates for the API server and the default Ingress Controller (*.apps). Browsers and CLI tools will show TLS warnings until you replace them with certificates signed by a trusted CA. You can replace them independently.

Planning note: Certificate replacement requires a Secret of type kubernetes.io/tls containing the full chain (cert + intermediates) and private key. Coordinate with the customer's PKI / security team β€” lead time for CA-signed certs can be days to weeks.
Certificate Chain & Placement Diagram
Certificate Placement in OpenShift Root / Intermediate CA Corporate PKI or Public CA (DigiCert, etc.) API Server Certificate SAN: api.<cluster>.<base> Port 6443 Additional Trust CA Bundle Injected into all pods for proxy or internal CA trust Ingress Wildcard Cert SAN: *.apps.<cluster>.<base> Port 443 Secret in openshift-config APIServer.spec.servingCerts ConfigMap in openshift-config proxy.spec.trustedCA Secret in openshift-ingress IngressController.spec.defaultCertificate Default: self-signed certs auto-generated by OCP β€” replace for trusted TLS API Server Additional Trust CA Ingress Wildcard

Default Ingress Certificate (*.apps)

Replaces the self-signed wildcard certificate used by the default IngressController for all Routes. Modern TLS clients validate SAN (Subject Alternative Name), not CN β€” the wildcard must appear in SAN.

Auto: *.apps.<cluster>.<base>
Auto: *.apps.<cluster>.<base> β€” must be in SAN, CN alone is not sufficient
Extra SANs beyond the wildcard
Replace default Ingress certificate
# 1. Create the TLS secret in openshift-ingress namespace
oc create secret tls apps-tls-cert \
  --cert=wildcard-apps.crt \
  --key=wildcard-apps.key \
  -n openshift-ingress

# Note: wildcard-apps.crt must contain the full chain:
#   - Server certificate (*.apps.ocp.example.com)
#   - Intermediate CA(s)
#   - (Optional) Root CA

# 2. Patch the IngressController to use the new certificate
oc patch ingresscontroller default \
  -n openshift-ingress-operator \
  --type=merge \
  -p '{"spec":{"defaultCertificate":{"name":"apps-tls-cert"}}}'

# 3. Verify β€” the router pods will restart automatically
oc get pods -n openshift-ingress -w

# 4. Test with curl
curl -v https://console-openshift-console.apps.ocp.example.com 2>&1 | grep issuer

API Server Certificate

Replaces the self-signed certificate used by the Kubernetes API server (api.<cluster>.<base>:6443). After replacement, oc login and kubeconfig clients will trust the API without --insecure-skip-tls-verify.

Auto: api.<cluster>.<base>
Replace API server certificate
# 1. Create the TLS secret in openshift-config namespace
oc create secret tls api-tls-cert \
  --cert=api-server.crt \
  --key=api-server.key \
  -n openshift-config

# Note: The certificate SAN must include:
#   - api.<cluster>.<base>  (e.g., api.ocp.example.com)
# The cert file should include the full chain (server + intermediates)

# 2. Patch the APIServer resource
oc patch apiserver cluster \
  --type=merge \
  -p '{"spec":{"servingCerts":{"namedCertificates":[{"names":["api.ocp.example.com"],"servingCertificate":{"name":"api-tls-cert"}}]}}}'

# 3. Monitor the kube-apiserver rollout (takes several minutes)
oc get co kube-apiserver -w

# 4. Verify
oc login https://api.ocp.example.com:6443 -u kubeadmin
# Should connect without TLS warnings if CA is trusted
Warning: API server certificate replacement triggers a rolling restart of kube-apiserver pods across all control plane nodes. This is non-disruptive for workloads but the API may be briefly unavailable during rollout (~5–10 minutes). Plan this during a maintenance window.
The installer-generated kubeconfig keeps working after replacement β€” it pins the internal CA, and the internal endpoints keep serving the internal cert. Use a separate certificate from the Ingress wildcard: api. must not be covered by *.apps., and reusing one cert for both couples two unrelated rotation lifecycles.

Additional Trusted CA Bundle

If your organization uses a private/internal CA (for proxy, registry, LDAP, etc.), add it to the cluster-wide trusted CA bundle so all components trust it. This is separate from the API/Ingress certs above.

Namespace: openshift-config
Add custom CA to cluster trust bundle
# 1. Create a ConfigMap with the CA bundle in openshift-config
oc create configmap user-ca-bundle \
  --from-file=ca-bundle.crt=corp-root-ca.pem \
  -n openshift-config

# Note: ca-bundle.crt can contain multiple PEM certificates concatenated

# 2. Patch the proxy/cluster resource to use the custom CA
oc patch proxy/cluster \
  --type=merge \
  -p '{"spec":{"trustedCA":{"name":"user-ca-bundle"}}}'

# This injects the CA into:
#   - All pods via the trusted-ca-bundle ConfigMap (if they opt in via label)
#   - Machine Config for node-level trust (RHCOS trust store)
#   - Proxy-aware components (image pulls, egress)

# 3. Verify the CA is distributed
oc get configmap trusted-ca-bundle -n openshift-config-managed -o yaml | head -20
Pods opt in by adding the label config.openshift.io/inject-trusted-cabundle: "true" to a ConfigMap. The Cluster Network Operator (CNO) then injects the merged system + custom CAs. This is how builds, S2I, and image registry connections pick up your internal CA.
cert-manager Operator: For automated lifecycle (issuance, renewal, revocation), install the cert-manager Operator for Red Hat OpenShift from OperatorHub. It supports ACME (Let's Encrypt), Venafi, Vault, and private CA issuers. Configure ClusterIssuer and Certificate CRs to auto-manage both Ingress and API certs.

Design Notes & Decisions