, ,

OpenShift OAuth, LDAP Group Sync and Registry Setup (TKGI to OpenShift Series, Part 15)

Login proves identity, and group membership does not arrive with it. Here is how to wire OpenShift OAuth to the directory behind TKGI, sync groups on a schedule, bind roles, and decide whether the internal image registry or Harbor serves your migration waves.

TKGI to OpenShift Series · Part 15 of 26

Your first directory user signs into the OpenShift console, lands on a working dashboard, and the migration feels finished. Then you run oc get groups and the cluster answers with No resources found.

That gap between authentication and authorization is where most Tanzu Kubernetes Grid Integrated (TKGI) teams lose a week. TKGI shipped User Account and Authentication (UAA) as its identity broker, and UAA handed group claims straight back in the token. OpenShift Container Platform (OCP) does not work that way. An identity provider proves who somebody is. Group membership arrives through a separate sync job you schedule yourself, and until that job runs, every migrated developer is an authenticated user holding exactly zero permissions.

Part 14 gave every team a Project with a quota around it. This part decides who can open that door, and where the container images behind it come from. Both answers need to land before wave one moves, because a workload nobody can pull and a developer who cannot log in look identical from a stakeholder chair.

Who this is for: You run an OCP 4 cluster on vSphere with Projects and MachineSets already in place from Part 14, you have an Active Directory or LDAP directory that TKGI reached through UAA, and you have a Harbor registry holding the images about to move. You still hold the kubeadmin password, and nobody outside the platform team has logged in yet.
Key takeaways:
1. Point OpenShift OAuth straight at your directory, never at UAA, because UAA gets decommissioned along with TKGI.
2. Authentication and group membership are two separate jobs. A login creates a User object, and only a sync creates a Group object.
3. Run group sync with a whitelist every single time, otherwise you import the entire directory into your cluster.
4. Image registry on vSphere starts Removed, and needs a Recreate rollout, one replica and a ReadWriteOnce claim before it serves anything.
5. ImageDigestMirrorSet ignores tag based pulls, and almost every manifest coming off TKGI pulls by tag. Headline command: oc adm groups sync –sync-config=sync-config.yaml –whitelist=ocp-groups.txt –confirm

Preflight and Versions Tested

Every command below ran against one combination, and drift on the directory side is the usual reason a copied snippet fails. Check yours before you start.

# Tested against: OCP 4.18.9, oc 4.18.9, TKGI 1.18.2, Harbor 2.11.1, # Active Directory on Windows Server 2022, vSphere 8.0 U3 with vSphere CSI. $ oc version Client Version: 4.18.9 Kustomize Version: v5.4.2 Server Version: 4.18.9 Kubernetes Version: v1.31.6 $ oc get clusterversion NAME VERSION AVAILABLE PROGRESSING SINCE STATUS version 4.18.9 True False 6d2h Cluster version is 4.18.9 # Prove the bind account works from a bastion BEFORE touching the cluster. # Password comes from an environment variable, never from the command line history. $ export LDAP_BIND_PW=$(cat /run/secrets/ocp-ldap-bindpw) $ ldapsearch -x -H ldaps://ldap.corp.example.com:636 -D ‘CN=svc-ocp-bind,OU=Service,DC=corp,DC=example,DC=com’ -w "$LDAP_BIND_PW" -b ‘OU=Users,DC=corp,DC=example,DC=com’ ‘(uid=asharma)’ dn cn mail uid # asharma, Users, corp.example.com dn: CN=Anita Sharma,OU=Users,DC=corp,DC=example,DC=com cn: Anita Sharma mail: asharma@corp.example.com uid: asharma # numEntries: 1

Three preflight facts decide whether this runbook is a twenty minute job or a two day one. You need a read only service account bind DN that can see both the user organizational unit and the group organizational unit, and it should not be your own account. You need the PEM encoded certificate authority that signed the directory server certificate, root and intermediates concatenated into one file. And you need to know exactly which attribute your directory uses for a short login name, because sAMAccountName and uid are not interchangeable, and choosing wrong hands every user a second identity three weeks later when somebody corrects it.

Wiring OAuth to Your Existing Directory

Step 1. Store the bind password and the certificate authority. OpenShift keeps identity provider material in the openshift-config namespace, separate from the OAuth resource that references it. Two objects, created once, reused by every identity provider you add later.

Step 2. Write the OAuth custom resource and apply it. A custom resource (CR) is a cluster object whose shape comes from an installed API rather than core Kubernetes. Only one OAuth object exists per cluster and it is always named cluster, so you are editing a singleton, not creating a new record. Note the id field set to dn. Distinguished names change rarely, short login names change often, and identity records in OpenShift are keyed on whatever you put in id.

Spend a minute on mappingMethod before you apply anything, because changing it afterwards is messy. Four values exist. Setting claim, which is the default, links an identity to a user carrying the same preferred user name and fails outright when that name already belongs to a different identity. Setting lookup uses only mappings you created yourself and refuses to create anything new, which suits regulated estates where user provisioning is a separate approval step. Setting add attaches the identity to an existing user of that name, joining accounts rather than colliding. Setting generate quietly invents a fresh name such as asharma2 whenever a collision happens, and that is how one person ends up with two accounts and a confused support ticket six weeks later. Use claim, and let a collision fail loudly during your pilot rather than silently during wave three.

$ oc create secret generic ldap-bind-secret –from-literal=bindPassword="$LDAP_BIND_PW" -n openshift-config secret/ldap-bind-secret created $ oc create configmap ldap-ca –from-file=ca.crt=/etc/pki/corp/corp-root-ca.pem -n openshift-config configmap/ldap-ca created $ cat oauth-cluster.yaml apiVersion: config.openshift.io/v1 kind: OAuth metadata: name: cluster spec: identityProviders: – name: corpldap mappingMethod: claim type: LDAP ldap: attributes: id: – dn email: – mail name: – cn preferredUsername: – uid bindDN: ‘CN=svc-ocp-bind,OU=Service,DC=corp,DC=example,DC=com’ bindPassword: name: ldap-bind-secret ca: name: ldap-ca insecure: false url: ‘ldaps://ldap.corp.example.com/OU=Users,DC=corp,DC=example,DC=com?uid’ $ oc apply -f oauth-cluster.yaml oauth.config.openshift.io/cluster configured # The authentication operator rolls the oauth-openshift pods. Wait for it. $ oc get co authentication -w NAME VERSION AVAILABLE PROGRESSING DEGRADED SINCE authentication 4.18.9 True True False 21s authentication 4.18.9 True False False 2m14s # First login attempt failed. Here is the real line, not a paraphrase. $ oc logs -n openshift-authentication deploy/oauth-openshift | tail -2 E0812 09:14:22.881304 1 basicauth.go:44] Error authenticating login for provider corpldap: LDAP Result Code 200 Network Error: x509: certificate signed by unknown authority # Cause: the configmap was created without the ca.crt= key prefix, so the # key was named corp-root-ca.pem and the operator silently ignored it. $ oc get configmap ldap-ca -n openshift-config -o jsonpath='{.data}’ | head -c 40 {"corp-root-ca.pem":"—–BEGIN CERTIF $ oc delete configmap ldap-ca -n openshift-config $ oc create configmap ldap-ca –from-file=ca.crt=/etc/pki/corp/corp-root-ca.pem -n openshift-config configmap/ldap-ca created # Green looks like this. $ oc login -u asharma https://api.ocp.corp.example.com:6443 Authentication required for https://api.ocp.corp.example.com:6443 (openshift) Username: asharma Password: Login successful. You do not have any projects. You can try to create a new project, by running: oc new-project <projectname>

That closing message is the whole problem in one sentence. Authentication worked. Authorization has not started.

Do not point OAuth at UAA: It is the first idea every TKGI team has, and it is the wrong one. UAA can speak OpenID Connect, so on paper you could register OpenShift as a client and keep one login surface during the transition. You would then have an OpenShift cluster whose ability to authenticate anybody depends on a Tanzu Operations Manager tile you are contractually committed to deleting. Migrate identity once, at the start, straight to the directory that UAA was itself proxying. Part 10 mapped the objects; this part wires them.

Group Sync, Because Login Alone Grants Nothing

OpenShift creates a User object and an Identity object the moment somebody authenticates. It creates no Group object, ever, from a login. Groups come from oc adm groups sync, a command you run on a schedule against a config file that describes your directory schema. Until it runs, every RoleBinding you wrote against a group name matches nobody.

flowchart TD
  A[User opens console] --> B[oauth openshift pod]
  B --> C{LDAP bind and search}
  C -- fails --> D[Login rejected, check ca.crt key and bindDN]
  C -- succeeds --> E[Identity and User objects created]
  E --> F{Group object exists from sync}
  F -- no --> G[Authenticated with zero roles, empty project list]
  F -- yes --> H[RoleBinding on Project matches the group]
  H --> I[oc and console actions authorized]
Login and authorization are separate paths. Branch F is the one that surprises TKGI operators, because UAA collapsed both into a single token.

Step 3. Write a sync config and a whitelist, then run the sync. Pick the schema section that matches your directory. Plain RFC 2307 stores membership on the group entry. Active Directory stores it on the user entry. Augmented Active Directory has first class group entries and user side membership attributes, which is what most enterprise AD deployments actually look like once somebody has added group naming. Group sync runs as a dry run by default, and the –confirm flag is the only thing that writes.

$ cat sync-config.yaml kind: LDAPSyncConfig apiVersion: v1 url: ldaps://ldap.corp.example.com:636 bindDN: ‘CN=svc-ocp-bind,OU=Service,DC=corp,DC=example,DC=com’ bindPassword: file: /run/secrets/ocp-ldap-bindpw ca: /etc/pki/corp/corp-root-ca.pem insecure: false augmentedActiveDirectory: groupsQuery: baseDN: ‘OU=Groups,DC=corp,DC=example,DC=com’ scope: sub derefAliases: never filter: ‘(objectClass=group)’ pageSize: 0 groupUIDAttribute: dn groupNameAttributes: [ cn ] usersQuery: baseDN: ‘OU=Users,DC=corp,DC=example,DC=com’ scope: sub derefAliases: never pageSize: 0 userNameAttributes: [ uid ] groupMembershipAttributes: [ memberOf ] $ cat ocp-groups.txt CN=ocp-platform-admins,OU=Groups,DC=corp,DC=example,DC=com CN=payments-dev,OU=Groups,DC=corp,DC=example,DC=com CN=payments-ops,OU=Groups,DC=corp,DC=example,DC=com # Dry run first. No –confirm means nothing is written. $ oc adm groups sync –sync-config=sync-config.yaml –whitelist=ocp-groups.txt group/ocp-platform-admins group/payments-dev group/payments-ops $ oc get groups No resources found # That empty result after a successful looking run is the trap. Add –confirm. $ oc adm groups sync –sync-config=sync-config.yaml –whitelist=ocp-groups.txt –confirm group/ocp-platform-admins group/payments-dev group/payments-ops $ oc get groups NAME USERS ocp-platform-admins pjha, rmenon payments-dev asharma, dmwangi, tokafor payments-ops asharma, kbenali

Run this on a CronJob, not from your laptop. A directory change that removes somebody from payments-ops does nothing to their OpenShift access until the next sync lands, and a sixty minute schedule is a reasonable starting point for a migration window. oc adm prune groups is the companion command that deletes Group objects whose directory record has disappeared.

Here is what skipping the whitelist looks like. On the staging cluster I ran the sync against the directory root, because writing out a whitelist file felt like paperwork on a Friday. Directory had 1,412 group entries inside that base DN. All 1,412 landed in OpenShift as Group objects, the console group picker turned into a scroll of distribution lists and printer queues, and two imported names collided with Projects the platform team had already created that morning. Cleanup took 40 minutes of scripted deletes plus one awkward message in the migration channel. Worth knowing: a second, correct run does not fix it. Groups outside the whitelist are not considered at all, so the junk simply stays until you remove it by hand.

Role Bindings and Self Service Project Control

Step 4. Bind roles to groups, never to users. Role Based Access Control (RBAC) in OpenShift attaches a role to a subject inside a scope. Bind to a group and the directory stays the source of truth. Bind to a user and you have built a second, silent access control system that nobody remembers to update when somebody moves teams. TKGI plans mapped to clusters; OpenShift roles map to Projects, and the three that cover most of a migrated estate are view, edit and admin.

Self service project creation is on by default, granted to every authenticated user through the self-provisioners cluster role binding. On a TKGI estate this is the wrong default. Your teams are used to asking for a cluster and receiving one, and Part 14 built a project request template with quotas already inside it. Leave self service on and developers route around that template within a week.

Choosing between admin and edit matters more than it looks on a role list. Granting edit lets somebody deploy, scale, read logs and manage config inside a Project, which covers nearly every developer task migrated off TKGI. Granting admin adds the power to hand access to other people, change the Project itself and rewrite its role bindings. On TKGI most teams held cluster level credentials, because a plan gave them a whole cluster of their own, so their instinct is to ask for admin everywhere and treat anything less as a demotion. Give edit to developer groups, admin to whoever genuinely owns the Project, and keep cluster-admin for a group small enough that you can name every member from memory. A migration is the one moment when nobody expects old permissions to carry across untouched, so spend that goodwill here.

$ oc adm policy add-cluster-role-to-group cluster-admin ocp-platform-admins clusterrole.rbac.authorization.k8s.io/cluster-admin added: "ocp-platform-admins" $ oc adm policy add-role-to-group edit payments-dev -n payments clusterrole.rbac.authorization.k8s.io/edit added: "payments-dev" $ oc adm policy add-role-to-group admin payments-ops -n payments clusterrole.rbac.authorization.k8s.io/admin added: "payments-ops" # Stop the cluster resetting self-provisioners on every upgrade, THEN remove it. # Order matters. Remove first and the operator restores it within minutes. $ oc patch clusterrolebinding.rbac self-provisioners –type=merge -p ‘{"metadata":{"annotations":{"rbac.authorization.kubernetes.io/autoupdate":"false"}}}’ clusterrolebinding.rbac.authorization.k8s.io/self-provisioners patched $ oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth clusterrole.rbac.authorization.k8s.io/self-provisioner removed: "system:authenticated:oauth" # Verify with impersonation instead of asking a developer to test it for you. $ oc auth can-i create pods -n payments –as=asharma yes $ oc auth can-i delete resourcequota -n payments –as=asharma no $ oc auth can-i create projectrequests –as=asharma no – no RBAC policy matched
Keep kubeadmin longer than the docs suggest: Standard advice is to delete the kubeadmin secret as soon as an identity provider works. Do not do it on the same day. Wait until a real human from your cluster-admin group has logged in through the directory, run a privileged command, and confirmed it worked after a group sync has cycled at least once. A mistyped bindDN plus a deleted kubeadmin secret means a support case, not a fix. Delete it in the following change window, not in the same one.

Registry Choice, Internal Beside Harbor

On vSphere the internal image registry ships switched off. vSphere installs do not provision shareable object storage, so the Image Registry Operator sets managementState to Removed and waits for you to give it somewhere to write. That is a decision point, not a chore, and the three real options behave very differently during a migration.

OptionWhat it costs youPick it when
Internal registry only, Harbor retired at cutoverRe-push or rebuild every image before wave one, plus a registry claim you now own, monitor and pruneHarbor is TKGI era infrastructure you also want to retire, and every image is rebuildable from a pipeline you control
Harbor only, internal registry left RemovedA pull secret in every Project, no ImageStreams, no source to image builds, and a hard dependency on a box outside the clusterHarbor is a shared corporate registry serving platforms beyond TKGI and has its own roadmap
Internal registry with Harbor as upstream mirrorTwo systems to watch for the length of the migration, plus mirror sets to maintain and retireYou are migrating in waves and want a rollback that does not involve re-pushing images at 2am. This is the pick.

Step 5. Turn the registry on, give it storage, and point pulls where you want them. Block storage on vSphere means ReadWriteOnce, ReadWriteOnce means one replica, and one replica means the Recreate rollout strategy. Apply that patch before you attach the claim, not after.

$ oc get co image-registry NAME VERSION AVAILABLE PROGRESSING DEGRADED MESSAGE image-registry 4.18.9 False True True Storage is not configured # I attached the claim first and skipped the rollout patch. Real result: $ oc get pods -n openshift-image-registry NAME READY STATUS RESTARTS AGE image-registry-7c9f8d4b6-h2mzq 1/1 Running 0 4m image-registry-7c9f8d4b6-w8ktp 0/1 Pending 0 4m $ oc describe pod image-registry-7c9f8d4b6-w8ktp -n openshift-image-registry | grep -A1 Warning Warning FailedAttachVolume 4m attachdetach-controller Multi-Attach error for volume "pvc-9c1f…" Volume is already exclusively attached to one node and cannot be attached to another # Fix the strategy and the replica count, then the claim. $ oc patch config.imageregistry.operator.openshift.io/cluster –type=merge -p ‘{"spec":{"rolloutStrategy":"Recreate","replicas":1}}’ config.imageregistry.operator.openshift.io/cluster patched $ cat registry-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: image-registry-storage namespace: openshift-image-registry spec: accessModes: – ReadWriteOnce resources: requests: storage: 250Gi storageClassName: thin-csi $ oc apply -f registry-pvc.yaml persistentvolumeclaim/image-registry-storage created $ oc patch config.imageregistry.operator.openshift.io/cluster –type=merge -p ‘{"spec":{"managementState":"Managed","storage":{"pvc":{"claim":"image-registry-storage"}}}}’ config.imageregistry.operator.openshift.io/cluster patched $ oc get co image-registry NAME VERSION AVAILABLE PROGRESSING DEGRADED MESSAGE image-registry 4.18.9 True False False # Redirect pulls without editing a single application manifest. # BOTH objects are needed. Digest pulls and tag pulls are matched separately. $ cat mirrors.yaml apiVersion: config.openshift.io/v1 kind: ImageDigestMirrorSet metadata: name: harbor-to-internal spec: imageDigestMirrors: – source: harbor.corp.example.com/payments mirrors: – image-registry.openshift-image-registry.svc:5000/payments — apiVersion: config.openshift.io/v1 kind: ImageTagMirrorSet metadata: name: harbor-to-internal-tags spec: imageTagMirrors: – source: harbor.corp.example.com/payments mirrors: – image-registry.openshift-image-registry.svc:5000/payments $ oc apply -f mirrors.yaml imagedigestmirrorset.config.openshift.io/harbor-to-internal created imagetagmirrorset.config.openshift.io/harbor-to-internal-tags created # Both write /etc/containers/registries.conf and roll every node. Watch it. $ oc get mcp worker NAME UPDATED UPDATING DEGRADED MACHINECOUNT READYMACHINECOUNT worker False True False 6 2

Applying an ImageDigestMirrorSet on its own is the single most common registry mistake I see on migrations, and it fails silently. Digest mirroring only matches image references pinned to a sha256 value. Manifests coming off a TKGI estate overwhelmingly pull by tag, because that is what a decade of Helm charts and CI templates produce. Pods keep resolving to Harbor, everybody assumes the mirror is working because nothing errored, and the dependency you were trying to remove is still load bearing on cutover day. Apply the tag mirror set too, then confirm on a node rather than in the API.

Registry sizing deserves a second look as well. Red Hat documentation uses 100Gi in its vSphere example, and a great many clusters get built with exactly that number copied across. During a migration you are not running a steady state registry. You are pushing every image from every wave, keeping older tags because rollback needs them, and accumulating build layers nobody prunes yet. Here is what one claim did across eight weeks of waves on the reference estate.

Image registry claim consumed, eight weeks of migration wavesReference estate, three TKGI clusters draining onto one OpenShift cluster. Values in GiB.100 GiB, the documented vSphere example18416896129171208244W1W2W3W4W5W6W7W8A 100 GiB claim runs out during week five, mid wave, with no online resize on some vSphere storage classes.
Registry growth is front loaded during a migration and flattens only after pruning is scheduled. Size for the migration, not for the steady state.

Start at 250Gi, and schedule the image pruner before wave three rather than after it runs out. Growth flattens once old tags start aging out, but that flattening does not happen on its own.

Verification, Rollback and Failure Remediation

Five checks tell you this part landed. Run them as a block, and treat any one of them coming back wrong as a stop signal for the wave.

# 1. Identity provider is live and not degraded. $ oc get co authentication NAME VERSION AVAILABLE PROGRESSING DEGRADED authentication 4.18.9 True False False # 2. Groups exist and carry the right members. $ oc get groups -o custom-columns=NAME:.metadata.name,USERS:.users NAME USERS ocp-platform-admins [pjha rmenon] payments-dev [asharma dmwangi tokafor] payments-ops [asharma kbenali] # 3. A real developer has exactly the access you intended. $ oc auth can-i –list -n payments –as=asharma | head -4 Resources Non-Resource URLs Resource Names Verbs pods [] [] [get list watch create update patch delete] deployments [] [] [get list watch create update patch delete] resourcequotas [] [] [get list watch] # 4. Registry serves a push and a pull from inside the cluster. $ oc registry login –skip-check $ oc get imagestream -n payments NAME IMAGE REPOSITORY TAGS payments image-registry.openshift-image-registry.svc:5000/payments v1.4.2 # 5. Mirror config actually reached the nodes. Check the node, not the API. $ oc debug node/worker-02 — chroot /host grep -A2 ‘harbor.corp.example.com/payments’ /etc/containers/registries.conf [[registry]] prefix = "" location = "harbor.corp.example.com/payments" [[registry.mirror]] location = "image-registry.openshift-image-registry.svc:5000/payments"

Rollback is straightforward here, which is unusual and worth using. Identity, RBAC and registry changes are all declarative singletons, so backing out means restoring a previous object rather than rebuilding anything. Keep a copy of the OAuth resource before you touch it, keep the kubeadmin secret until the following change window, and remember that removing a mirror set rolls every node again, so budget the same twenty to thirty minutes on the way out that you budgeted on the way in.

This table is the artifact worth keeping from this Part. Print it, or paste it into the runbook your on call rotation actually opens at 3am.

SymptomError you will actually seeFix
Every login rejectedLDAP Result Code 200 Network Error: x509 certificate signed by unknown authorityConfigMap key must be exactly ca.crt. Recreate with –from-file=ca.crt=/path/to/ca.pem
Login works, console shows no projectsNo error at all, just an empty project listNo Group objects exist yet. Run group sync, then bind roles to the groups
Sync prints group names, oc get groups stays emptyNo error, output looks identical to a real runSync is dry run by default. Add –confirm
self-provisioner comes back after removalBinding silently reappears within minutesSet rbac.authorization.kubernetes.io/autoupdate to false BEFORE removing it
Image registry operator DegradedDegraded: Storage is not configuredvSphere leaves managementState Removed. Patch to Managed and attach a claim
Second registry pod Pending foreverMulti-Attach error for volume, already exclusively attached to one nodeReadWriteOnce allows one replica. Patch rolloutStrategy to Recreate and replicas to 1
Pods still pull from Harbor after mirroringNo error, pulls simply resolve to the sourceImageDigestMirrorSet matches digests only. Add an ImageTagMirrorSet
Duplicate users after a directory tidy upTwo Identity objects mapping to one person, one with no rolesKeep id set to dn so identity survives a login name change

A clean result looks like this. Authentication operator available and not progressing. Three Group objects with the members you expect and nothing else. A developer who can create a pod in their Project and cannot create a project. An image-registry cluster operator reporting True, False, False, backed by a claim sized for a migration rather than a demo. And a mirror stanza visible in the container runtime config on a worker node, not just an accepted object in the API server.

Directory First, Registry Second, Kubeadmin Last

My recommendation for this stage is a strict order, and it survives contact with real estates. Wire OAuth to the directory that UAA was already proxying, and skip any idea of keeping UAA in the path. Sync groups with a whitelist on a CronJob before you write a single RoleBinding. Bind roles to groups only. Turn off self service project creation so the quota template from Part 14 keeps meaning something. Stand up the internal registry with Harbor mirrored behind both an ImageDigestMirrorSet and an ImageTagMirrorSet, sized at 250Gi. Then, in the next change window and not this one, delete kubeadmin.

Teams that reach this point sometimes reconsider the whole landing place, and that is a fair moment to do it. If your organisation is heading toward VMware Cloud Foundation 9 rather than Red Hat, the equivalent work is covered in the TKGI to VKS Series instead. Everyone else carries on. Next up is network policy and microsegmentation, translating NSX-T distributed firewall rules into OVN-Kubernetes NetworkPolicy, which is where the security team finally gets involved.

One thing to do on Monday: run oc get groups on whatever OpenShift cluster you already have. If it comes back empty while people are logging in successfully, you have found the same gap, and you now know it takes a sync config and a whitelist to close it. Related reading in this series: Part 10 on identity and multi-tenancy design, and Part 7 on Security Context Constraints, because admission is the next thing that will reject a workload after RBAC lets it through.

TKGI to OpenShift Series · Part 15 of 26
« Previous: Part 14  |  Guide  |  Next: Part 16 »

References

About The Author


Discover more from Journal of Intelligent Infrastructure

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure

Subscribe now to keep reading and get access to the full archive.

Continue reading