There is a special kind of chaos that appears the moment someone says, “Can we just hook OpenShift up to Active Directory?” On paper, it sounds simple. In practice, it usually means certificates, bind accounts, LDAP filters, group mappings, and at least one moment where you stare at the authentication operator wondering if it is judging you.
The good news: this is very doable, and once it is in place, it makes OpenShift feel a lot more like part of the rest of the environment instead of a walled garden.
This walkthrough covers the process we used to:
- configure LDAP as an authentication source in OpenShift
- sync AD groups into OpenShift
- bind those groups to OpenShift roles
- validate that the configuration actually worked
Sanitized examples: I replaced real domains, names, and any IP references with generic values. In the examples below, I use
example.com,api.ocp.example.com, and RFC 5737 sample IP space like192.0.2.10where an IP example is helpful.
Prerequisites
Before touching cluster authentication, make sure you have the following:
- cluster-admin access to OpenShift
- an AD service account that can search LDAP
- the AD/LDAP CA certificate exported to a file
- the LDAP endpoint reachable from the cluster, typically
ldaps://ad01.example.com:636 - the AD groups you want to map to OpenShift access already created
In our case, we had the CA certificate available locally as cert/ad-ca.cer.
Step 1: Store the LDAP bind password and CA certificate in OpenShift
OpenShift needs two things before it can talk to AD securely:
- a secret containing the bind password
- a config map containing the CA certificate that signed the LDAP server certificate
We created those with the CLI.
read -rsp 'LDAP bind password: ' LDAP_BIND_PASSWORD; echo
oc -n openshift-config create secret generic ldap-bind-password \
--from-literal=bindPassword="$LDAP_BIND_PASSWORD" \
--dry-run=client -o yaml | oc apply -f -
unset LDAP_BIND_PASSWORD
oc -n openshift-config create configmap ldap-ca \
--from-file=ca.crt=cert/ad-ca.cer \
--dry-run=client -o yaml | oc apply -f -
That gave us two reusable objects:
- secret:
ldap-bind-password - config map:
ldap-ca
Step 2: Back up the existing OAuth config
Before changing authentication, I strongly recommend taking a backup of the cluster OAuth object. It is a tiny step that feels unnecessary right up until the moment it becomes very necessary.
oc get oauth cluster -o yaml > oauth-cluster-backup.yaml
Step 3: Configure LDAP as the OpenShift identity provider
Next came the actual identity provider configuration. We applied an OAuth object that pointed OpenShift at Active Directory over LDAPS.
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
name: cluster
spec:
identityProviders:
- name: corp-ad
mappingMethod: claim
type: LDAP
ldap:
url: "ldaps://ad01.example.com:636/DC=example,DC=com?userPrincipalName?sub?(&(objectClass=user)(objectCategory=person))"
bindDN: "CN=svc-openshift,OU=Service Accounts,DC=example,DC=com"
bindPassword:
name: ldap-bind-password
ca:
name: ldap-ca
insecure: false
attributes:
id:
- dn
preferredUsername:
- userPrincipalName
name:
- cn
email:
- mail
We applied it like this:
cat <<'EOF' | oc apply -f -
apiVersion: config.openshift.io/v1
kind: OAuth
metadata: {name: cluster}
spec:
identityProviders:
- name: corp-ad
mappingMethod: claim
type: LDAP
ldap:
url: "ldaps://ad01.example.com:636/DC=example,DC=com?userPrincipalName?sub?(&(objectClass=user)(objectCategory=person))"
bindDN: "CN=svc-openshift,OU=Service Accounts,DC=example,DC=com"
bindPassword: {name: ldap-bind-password}
ca: {name: ldap-ca}
insecure: false
attributes: {id: ["dn"], preferredUsername: ["userPrincipalName"], name: ["cn"], email: ["mail"]}
EOF
Why these settings matter
ldaps://keeps the traffic encrypted.userPrincipalNamemakes logins predictable for users.mappingMethod: claimtells OpenShift how to associate the LDAP identity with the OpenShift user.- the CA config map allows OpenShift to trust the AD certificate chain.
Step 4: Verify the authentication rollout
After applying the new OAuth config, we checked that the authentication operator and pods settled down cleanly.
oc get oauth cluster -o yaml
oc get co authentication
oc get pods -n openshift-authentication
If something looks off here, the next place to look is the OAuth pod logs:
oc -n openshift-authentication logs <oauth-pod-name> --since=30m | egrep -i 'ldap|error|fail|invalid|bind'
Step 5: Sync AD groups into OpenShift
Authentication gets users into the cluster, but authorization is where the real day-two value shows up. We wanted AD groups to drive OpenShift access, so we used oc adm groups sync with the augmentedActiveDirectory schema.
First, we created a whitelist of the exact AD groups we wanted to sync.
SYNC_DIR="$HOME/ldap-sync"
mkdir -p "$SYNC_DIR"
cat > "$SYNC_DIR/whitelist.txt" <<'EOF'
CN=ocp-cluster-admins,OU=Groups,DC=example,DC=com
CN=ocp-app-editors,OU=Groups,DC=example,DC=com
EOF
Then we created the sync config.
read -rsp 'LDAP bind password: ' LDAP_BIND_PASSWORD; echo
umask 077; printf '%s' "$LDAP_BIND_PASSWORD" > "$SYNC_DIR/bindPassword.txt"
unset LDAP_BIND_PASSWORD
cat > "$SYNC_DIR/ldap-sync.yaml" <<EOF
kind: LDAPSyncConfig
apiVersion: v1
url: ldaps://ad01.example.com:636
bindDN: "CN=svc-openshift,OU=Service Accounts,DC=example,DC=com"
bindPassword: {file: "$SYNC_DIR/bindPassword.txt"}
ca: /path/to/ad-ca.cer
augmentedActiveDirectory: {groupsQuery: {derefAliases: never, pageSize: 0}, groupUIDAttribute: dn, groupNameAttributes: [cn], usersQuery: {baseDN: "DC=example,DC=com", scope: sub, derefAliases: never, filter: "(objectClass=person)", pageSize: 0}, userNameAttributes: [userPrincipalName], groupMembershipAttributes: ["memberOf:1.2.840.113556.1.4.1941:"]}
EOF
That final membership attribute is the magic that makes nested AD group membership much less painful.
Before committing the sync, we ran a dry run:
oc adm groups sync --type=ldap \
--whitelist="$SYNC_DIR/whitelist.txt" \
--sync-config="$SYNC_DIR/ldap-sync.yaml"
And once the output looked right, we ran the real sync:
oc adm groups sync --type=ldap \
--whitelist="$SYNC_DIR/whitelist.txt" \
--sync-config="$SYNC_DIR/ldap-sync.yaml" \
--confirm
At that point, the OpenShift groups existed and could be used for RBAC.
Step 6: Bind AD-backed groups to OpenShift roles
This is where things finally start feeling civilized.
We bound one AD group to the cluster-admin cluster role and another group to the edit role inside an application namespace.
oc adm policy add-cluster-role-to-group cluster-admin ocp-cluster-admins
oc adm policy add-role-to-group edit ocp-app-editors -n project-a
That gave us a nice split:
ocp-cluster-admins= full cluster administrationocp-app-editors= namespace-scoped edit rights inproject-a
This pattern is simple, understandable, and easy to explain to both platform teams and the Windows/AD folks who now want to know what their group is doing in Kubernetes.
Quick validation checks
Once the sync and bindings were done, these were the quick sanity checks:
oc get group
oc get group ocp-cluster-admins
oc get group ocp-app-editors
oc get clusterrolebinding | grep ocp-cluster-admins
oc -n project-a get rolebinding | grep ocp-app-editors
If those objects exist and the OAuth operator is healthy, you are in a pretty good place.
Final thoughts
Hooking OpenShift into Active Directory is one of those projects that sounds like “just authentication,” but it quietly becomes an identity, trust, and authorization exercise all at once. The trick is to break it into clean layers:
- trust the LDAP endpoint
- authenticate users through OAuth
- sync the groups you actually care about
- let RBAC do the rest
Once that is in place, onboarding gets easier, access reviews make more sense, and OpenShift stops feeling like yet another island of accounts someone forgot to federate.
And honestly, that is the best outcome for this kind of work: fewer mystery users, fewer one-off permissions, and a lot less jungle. Next on the list, setting up a cron job to sync the groups as they change in AD.