Integrate OpenShift with Active Directory for Authentication

In this tutorial, you will learn how to integrate OpenShift with Active Directory for authentication. This setup enables users to log in to OpenShift using their existing AD credentials, streamlining access and enhancing security through centralized identity management. By following this guide, you’ll configure OpenShift to leverage AD’s robust user and group management capabilities, ensuring a unified and efficient authentication process across your organization’s infrastructure.

Integrate OpenShift with Active Directory for Authentication

By default, a fresh OpenShift installation provides a single administrative user, kubeadmin, which is intended for initial cluster setup and configuration. However, relying solely on kubeadmin or manually managing individual user accounts within OpenShift is impractical and insecure for enterprise environments. Integrating OpenShift with Active Directory (AD) for authentication addresses these limitations and offers several critical benefits:

  • Centralized Identity Management: Use existing AD accounts hence no need to create separate OpenShift users.
  • Enterprise-Grade Security: Leverage AD features like password policies, account lockouts…
  • Scalability: Manage access based on AD group membership, simplifying role assignments in large environments.
  • Improved User Experience: Enable single sign-on (SSO) with familiar AD credentials.
  • Compliance & Auditing: Centralized authentication supports regulatory compliance (e.g., GDPR, HIPAA).
  • Eliminates kubeadmin Dependency: Replace the insecure default user with a trusted identity provider.
  • and many more…

Prerequisites

Before beginning the integration, ensuring the following are in place is a critical step to successfully integrate OpenShift with Active Directory for Authentication in your environment:

  • A running OpenShift Container Platform (this guide uses OCP v4.19). You can check our guide on how to deploy OpenShift on User-provisioned infrastructure.
  • Active Directory Domain Services running on Windows Server (we are running AD on Windows Server 2025).
  • Network connectivity between OpenShift cluster and AD domain controllers.
  • DNS resolution configured for both AD and OpenShift endpoints.
  • SSL certificates for secure LDAP connections (recommended).
  • Cluster administrator privileges on OpenShift.
  • Domain administrator or delegated permissions in Active Directory.
  • Service account in AD for LDAP bind operations (read-only permissions sufficient).
  • User Mapping Strategy: Decide whether to use AD usernames or unique identifiers (UPN recommended).
  • Group Structure: Plan which AD groups will map to OpenShift roles.
  • Security Boundaries: Determine which OUs and groups should have access.
  • Naming Conventions: Establish consistent naming for OpenShift users and groups.

Understanding OpenShift Authentication Architecture

OpenShift’s authentication system consists of several key components that work together to provide secure access control:

Core Components:

The following core components form the foundation of OpenShift’s authentication and authorization architecture.

  • OAuth Server: This is the central authentication service in OpenShift that handles login requests and token generation. It validates credentials against configured identity providers and issues OAuth tokens for accessing the OpenShift API. It exposes two primary endpoints:
    • /oauth/authorize which initiates the OAuth authorization flow. When a user or application requests access, they are redirected to this endpoint to authenticate and grant permission.
    • /oauth/token which is used by clients to exchange authorization codes or credentials for access tokens, which are then used for authenticated API requests.
  • Identity Providers: These are the pluggable authentication backends responsible for verifying user credentials. For Active Directory integration, the LDAP identity provider is typically used to connect OpenShift to the AD server. There are other providers such as keystone, basic authentication, htpasswd, OIDC…Read more on Red Hat OpenShift supported identity providers.
  • User and Identity Objects: OpenShift creates internal user objects and links them to identity objects that represent external authentication sources (like AD). This separation enables multiple identity providers to map to the same OpenShift user if needed.
  • Role-Based Access Control (RBAC): OpenShift handles authorization through Kubernetes-native RBAC. Permissions are assigned using Roles, ClusterRoles, and their respective RoleBindings and ClusterRoleBindings.

OpenShift Authentication Flow

OpenShift authentication follows the sequence below when using an external identity provider (e.g., Active Directory) for user login:

  • User Initiates Access: The user attempts to access OpenShift via the web console (browser) or CLI (oc login), sending a request to the OAuth server’s /oauth/authorize endpoint.
  • OAuth Server Redirects to Identity Provider: The OAuth server then redirects the user to the configured identity provider (e.g., LDAP for Active Directory) using the OAuth 2.0 authorization code flow over a TLS-secured connection.
  • Identity Provider Validates Credentials: The LDAP provider authenticates the user against Active Directory, mapping attributes like sAMAccountName or userPrincipalName for user identity and memberOf for group membership. Invalid credentials result in an error, and the OAuth server denies access.
  • User and Identity Object Management: Upon successful authentication, the OAuth server creates or updates an Identity object for the external identity and maps it to an internal User object. Existing User objects are updated to support single sign-on (SSO) across multiple identity providers.
  • Token Issuance: The OAuth server issues an OAuth 2.0 access token (short-lived, for API access) and a refresh token (longer-lived, for session renewal) via the /oauth/token endpoint. These tokens are used as Bearer tokens in API request headers.
  • RBAC Permission Evaluation: For each API request, OpenShift’s RBAC system evaluates permissions based on RoleBindings or ClusterRoleBindings, including group-based roles from Active Directory group mappings. Access is granted or denied as per defined Roles or ClusterRoles (e.g., admin, view).

Active Directory Integration Methods

OpenShift’s authentication system, built on OAuth 2.0 and Kubernetes, supports multiple methods for integrating with Active Directory via pluggable identity providers. Below are the primary methods for AD integration, along with their configurations, benefits, and considerations.

  • LDAP Identity Provider: The LDAP identity provider offers the most direct and widely-supported method for Active Directory integration. It uses standard LDAP(S) protocols to authenticate users and can retrieve user attributes for profile information.
  • OpenID Connect (OIDC) with AD Federation Services (ADFS): OpenShift can integrate with AD via OpenID Connect (OIDC) using Active Directory Federation Services (ADFS) as an OIDC provider. ADFS acts as a bridge, authenticating users against AD and issuing OIDC tokens.
  • RequestHeader Identity Provider (Proxy-Based Integration): The RequestHeader identity provider allows OpenShift to trust authentication headers set by a reverse proxy or load balancer that integrates with AD. This is less common but useful in environments with existing proxy-based authentication.
  • SAML 2.0 with ADFS: OpenShift supports SAML 2.0 integration with AD via ADFS as a SAML identity provider. SAML is an alternative to OIDC for SSO, commonly used in enterprise environments.

We will use LDAP identity provider for integrating with AD in this guide.

Step by Step Guide to AD for Authentication

This section provides a detailed process to integrate OpenShift with Active Directory for authentication.

Step 1: Configure Bind DN Account in Windows AD

To allow OpenShift to authenticate users against Active Directory via LDAP, it needs a service account, commonly referred to as a Bind DN, with permission to search the directory tree.

This account is used by OpenShift (via the LDAP identity provider) to:

  • Connect to AD securely
  • Perform user lookups
  • Resolve group membership (if group-based access is configured)

We have created a BIND DN in our AD;

Get-ADUser -Identity read-only | Select-Object DistinguishedName

Replace read-only with the correct username (sAMAccountName) of your BIND DN account.

Sample output;


DistinguishedName
-----------------
CN=read-only,OU=ServiceAccounts,DC=kifarunix,DC=com

If you haven’t created your BIND DN, refer here; Create BIND DN User for Application Authentication.

Step 2: Verify AD Bind DN Connectivity from the Bastion Host

Before integrating Active Directory (AD) with OpenShift, it’s important to verify that your Bind DN account can successfully connect and authenticate to the AD server over LDAPS. In this setup, we’re performing the test from the Bastion Host, which has network access to the AD environment and is used to manage the OpenShift cluster.

To test the BIND DN connection, you need to ensure that the LDAP utilities are installed on your Bastion Host or any node from which you are performing the test.

On RHEL/CentOS/Fedora systems, you can install the required utilities using the following command:

sudo yum install openldap-clients

On Ubuntu/Debian systems, you can install the utilities using:

sudo apt install ldap-utils

Next, ensure that the CA certificate for your Active Directory server is imported onto the host where you’ll run the tests (e.g., Bastion Host). This is necessary to establish trust and prevent certificate validation errors during the LDAP connection.

Once the CA certificate is imported, you can perform a test query to verify connectivity and authentication for your Bind DN account:

ldapsearch -x -D "cn=read-only,ou=ServiceAccounts,dc=kifarunix,dc=com" \
	-W -H ldaps://dc01.kifarunix.com:636 \
	-b "ou=accessgroups,dc=kifarunix,dc=com" dn -LLL

Here is a break down of the command;

  • -x: Use simple authentication instead of SASL.
  • -D "cn=read-only,ou=ServiceAccounts,dc=kifarunix,dc=com": The Bind DN you created in AD (this is the account you’re testing).
  • -W: Prompts for the password for the Bind DN.
  • -H ldaps://dc01.kifarunix.com:636: The LDAP server (using LDAPS for secure communication over port 636).
  • -b "ou=accessgroups,dc=kifarunix,dc=com": The Base DN of the AD domain (this specifies where to begin searching).
  • dn: Only retrieve the DN (Distinguished Name) for each object found.
  • -LLL: Format the output to remove extra metadata and show only the search results.

If the Bind DN is valid and the connection is successful, you should see a list of distinguished names (DNs) of the objects found in the search base. If there are issues with the Bind DN, you may encounter errors like “Invalid credentials” or “Unable to connect.”

Sample results in my case:

dn: OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-Admins,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-Infra,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-Developers,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-CyberSec,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-ViewOnly,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=ERP-Admins,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=DBA-Admins,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-All,OU=AccessGroups,DC=kifarunix,DC=com

This confirms that the BIND DN works fine.

Our Active Directory Group Structure for OpenShift
In our Active Directory (AD) setup, OpenShift-related security groups are organized under the OU=AccessGroups,DC=kifarunix,DC=com organizational unit. This OU is primarily used to store access control groups, including those mapped to OpenShift roles. Within this OU, we use a parent group called OCP-All, which contains all individual OpenShift-related groups such as OCP-Admins, OCP-Infra, OCP-Developers, OCP-CyberSec, and others. This structure allows us to manage OpenShift access in a centralized and scalable manner such that new groups can be added in AD and included in OpenShift access simply by nesting them under the OCP-All group, without needing to modify the OpenShift configuration. While directory structures may vary across organizations, administrators have the flexibility to design a group hierarchy that best fits their environment and use cases.

If you’re using LDAPS (recommended for secure communication), OpenShift must trust the certificate authority (CA) used by your AD server.

This step is required because:

  • OpenShift’s OAuth server has to connects over TLS to the AD LDAP endpoint (ldaps://...).
  • If the AD server uses a self-signed or internal CA, OpenShift needs that CA certificate to validate the connection.

To install the CA certificate:

  1. Export the root CA certificate from your AD server. Refer here for the process.
  2. Ensure the certificate file is available on your Bastion Host or wherever you are running the oc commands. I have exported the certificate already and it is on my bastion host current working directory as ad-cs-root-ca.crt.
    ls -alh ad-ldaps-ca.crt
    -rw-rw-r-- 1 kifarunix kifarunix 1.3K Aug 19 13:08 ad-ldaps-ca.crt
  3. Create a ConfigMap in OpenShift with the certificate. See below.

After exporting the certificate from the Active Directory server, create a ConfigMap in the openshift-config namespace using the certificate:

If you are working from the CLI or using the web console, ensure are logged in as a user with proper rights.

oc create configmap ad-ldaps-ca-cert \
  --from-file=ca.crt=./ad-ldaps-ca.crt \
  -n openshift-config

Replace the path and the name of the ca certificate accordingly.

We will reference this ConfigMap in the LDAP identity provider configuration later.

Step 4: Create LDAP Bind Secret in OpenShift

Next, you’ll need to store the Bind DN password as a Kubernetes secret in OpenShift. We’ll do this using the CLI. Hence:

read -s BIND_DN_PASS
oc create secret generic ad-binddn-secret \
  --from-literal=bindPassword="$BIND_DN_PASS" \
  -n openshift-config
unset BIND_DN_PASS

Step 5: Configure LDAP Identity Provider in OpenShift

To enable OpenShift to authenticate users against Active Directory via LDAP, you must configure an identity provider (IdP) in the OpenShift OAuth system.

This is done by modifying the default OAuth custom resource (CR) named cluster, which already exists in every OpenShift cluster. In the Custom Resource, you define how OpenShift should:

  • Connect to the LDAP server
  • Authenticate users
  • Optionally filter or map user group membership
Please Note!
Applying a full OAuth custom resource like the one below will replace the entire identityProviders list in the existing OAuth configuration. If your cluster already has other identity providers configured (e.g., htpasswd, GitHub), you will lose them unless you include them in the new list. To avoid losing existing settings, back up the current configuration first:
oc get oauth cluster -o yaml > oauth-cluster-backup.yaml

Below is the sample updated Identity Provider (IdP) configuration we’ll apply to the OpenShift cluster:

cat ad-idp-cr.yaml
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
  name: cluster
spec:
  identityProviders:
  - name: win-ad-idp
    mappingMethod: claim
    type: LDAP
    ldap:
      attributes:
        id: [ sAMAccountName ]
        email: [ mail ]
        name: [ displayName ]
        preferredUsername: [ sAMAccountName ]
      bindDN: "cn=read-only,ou=ServiceAccounts,dc=kifarunix,dc=com"
      bindPassword:
        name: ad-binddn-secret
      ca:
        name: ad-ldaps-ca-cert
      insecure: false
      url: "ldaps://dc01.kifarunix.com:636/DC=kifarunix,DC=com?sAMAccountName?sub?(&(objectClass=person)(memberOf:1.2.840.113556.1.4.1941:=CN=OCP-All,OU=AccessGroups,DC=kifarunix,DC=com))"

This Custom Resource (CR) integrates OpenShift with an LDAP server (Active Directory) over LDAPS and maps user attributes to OpenShift identities.

  • Resource Type: OAuth configuration for the OpenShift cluster.
  • Identity Provider Name: win-ad-idp
  • Mapping Method: claim – maps LDAP attributes (e.g., username, email) directly to OpenShift user identities.
  • LDAP Bind DN: The service account (cn=read-only,ou=ServiceAccounts,...) used to perform LDAP queries.
  • Bind Password: Stored securely in a Kubernetes secret named ad-binddn-secret.
  • CA Certificate: References a ConfigMap named ad-ldaps-ca-cert containing the trusted CA certificate for secure LDAPS communication.
  • LDAP URL: Uses secure LDAPS (ldaps://) to connect to the domain controller. The LDAP search filter includes:
    • objectClass=person: Ensures only user objects are queried.
    • memberOf:1.2.840.113556.1.4.1941:=...: Recursively checks group membership for CN=OCP-All, which simplifies access control by allowing any nested group under OCP-All to authenticate.
    • Note: The LDAP URL should be designed to strike a balance between security and flexibility, allowing authorized users to authenticate without requiring frequent changes to the IdP configuration.

Once you’re ready, apply the updated OAuth Custom Resource:

oc apply -f ad-idp-cr.yaml
Note
If a CR does not exist, oc apply creates a new CR and might trigger the following warning:
Warning: resource oauths/cluster is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by oc apply. oc apply should only be used on resources created declaratively by either oc create --save-config or oc apply. The missing annotation will be patched automatically.
In this case, you can safely ignore this warning.

You can check that the IdP was applied correctly:

oc get oauth cluster -o yaml
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
  annotations:
    include.release.openshift.io/ibm-cloud-managed: "true"
    include.release.openshift.io/self-managed-high-availability: "true"
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"config.openshift.io/v1","kind":"OAuth","metadata":{"annotations":{},"name":"cluster"},"spec":{"identityProviders":[{"ldap":{"attributes":{"email":["mail"],"id":["sAMAccountName"],"name":["displayName"],"preferredUsername":["sAMAccountName"]},"bindDN":"cn=read-only,ou=ServiceAccounts,dc=kifarunix,dc=com","bindPassword":{"name":"ad-binddn-secret"},"ca":{"name":"ad-ldaps-ca-cert"},"insecure":false,"url":"ldaps://dc01.kifarunix.com:636/DC=kifarunix,DC=com?sAMAccountName?sub?(\u0026(objectClass=person)(memberOf:1.2.840.113556.1.4.1941:=CN=OCP-All,OU=AccessGroups,DC=kifarunix,DC=com))"},"mappingMethod":"claim","name":"win-ad-idp","type":"LDAP"}]}}
    release.openshift.io/create-only: "true"
  creationTimestamp: "2025-08-06T07:57:46Z"
  generation: 10
  name: cluster
  ownerReferences:
  - apiVersion: config.openshift.io/v1
    kind: ClusterVersion
    name: version
    uid: 5d9a1e8a-ad5f-464b-9dbe-fa0149fd0417
  resourceVersion: "4187155"
  uid: 4a99f9d9-aa4e-4eec-b5f8-14b3f49155eb
spec:
  identityProviders:
  - ldap:
      attributes:
        email:
        - mail
        id:
        - sAMAccountName
        name:
        - displayName
        preferredUsername:
        - sAMAccountName
      bindDN: cn=read-only,ou=ServiceAccounts,dc=kifarunix,dc=com
      bindPassword:
        name: ad-binddn-secret
      ca:
        name: ad-ldaps-ca-cert
      insecure: false
      url: ldaps://dc01.kifarunix.com:636/DC=kifarunix,DC=com?sAMAccountName?sub?(&(objectClass=person)(memberOf:1.2.840.113556.1.4.1941:=CN=OCP-All,OU=AccessGroups,DC=kifarunix,DC=com))
    mappingMethod: claim
    name: win-ad-idp
    type: LDAP

When you apply the changes, OpenShift will trigger a restart the OAuth server pods automatically in the openshift-authentication project/namespace:

oc get pod -n openshift-authentication
NAME                               READY   STATUS    RESTARTS   AGE
oauth-openshift-9965df6cd-7j7mh   1/1     Running   0          36s
oauth-openshift-9965df6cd-8h7mq   1/1     Running   0          63s
oauth-openshift-9965df6cd-gvc7g   1/1     Running   0          82s

Configure IdP on OpenShift Web Console

You can also configure AD integration from the OpenShift web console.

Login as admin user and head over to:

  • Administration > Cluster Settings > Configuration
  • Scroll down and click OAuth configuration resource
  • Under Identity Providers, you can add new IdP or remove existing ones:
    add Openshift Idp from web console
  • Click Add drop down and select your respect IdP from the list. For this specific case, select LDAP.
  • Provide required details:
    • Name: A unique name for the identity provider (e.g., win-ad-idp). This value cannot be changed once the provider is created.
    • URL: An RFC 2255-compliant LDAP URL that defines how OpenShift should search for users in Active Directory. Check URL we used above.
    • Bind DN: The distinguished name (DN) of the service account OpenShift will use to bind to LDAP for performing user lookups. Check our DN above.
    • Bind Password: The password for the bind DN account. This will be stored securely in a Kubernetes secret.
    • Attributes: Maps LDAP attributes to OpenShift user identity fields:
      • ID: LDAP attribute(s) used as the unique user ID (e.g., sAMAccountName)
      • Preferred Username: Attribute(s) used as the OpenShift username (commonly also sAMAccountName)
      • Name: Attribute(s) used to populate the user’s full display name (e.g., displayName)
      • Email: Attribute(s) used for the user’s email address (e.g., mail)
    • CA File (optional): If using ldaps, you must provide the root CA certificate of the AD/LDAP server to establish trust. From the command line, you can cat and paste the contents of your CA cert.
    • After entering all required values, click Add to create the identity provider, or Cancel to discard changes.

Step 6: Validate AD Connectivity and Test AD User Login on OpenShift

After configuring the LDAP identity provider for AD in OpenShift, it’s critical to verify that the integration works correctly. This step confirms:

  • The Active Directory connection (including certificates and bind credentials) is functional.
  • AD users can successfully authenticate and log in.

Validating these early helps detect any issues with LDAP filters, credentials, or certificate trust before users start accessing production resources.

Verify Bind DN Connectivity to Active Directory from OAuth Server Pods

Before testing AD user logins on OpenShift, confirm that the OpenShift OAuth server pods can reach Active Directory over LDAPS using the configured Bind DN credentials. This step ensures that the OpenShift authentication components can successfully connect to the AD server.

oc get pods -n openshift-authentication
NAME                              READY   STATUS    RESTARTS   AGE
oauth-openshift-9965df6cd-7j7mh   1/1     Running   0          11m
oauth-openshift-9965df6cd-8h7mq   1/1     Running   0          12m
oauth-openshift-9965df6cd-gvc7g   1/1     Running   0          12m

So, login to one of the pods:

oc rsh -n openshift-authentication oauth-openshift-9965df6cd-7j7mh

You will drop into the Pods shell. You can verify the OS and install required LDAP utilities as mentioned above.

sh-5.1# cat /etc/os-release | head -n2
NAME="Red Hat Enterprise Linux"
VERSION="9.4 (Plow)"
sh-5.1#

Since this is a RHEL 9, let’s install openldap-clients packages:

yum install openldap-clients -y

Next, use ldapsearch command to test the connection and authentication to your AD server. Since we’re using LDAPS, and have created a ConfigMap containing the AD LDAPS CA root certificate in the previous step (Step 5), this certificate is stored inside the OAuth pod at the following path:

/var/config/user/idp/0/configMap/v4-0-config-user-idp-0-ca/ca.crt

Similarly, the bind password created via the secret in step 4 is stored at:

/var/config/user/idp/0/secret/v4-0-config-user-idp-0-bind-password/bindPassword

The 0 in both paths corresponds to the position of the identity provider in the OAuth configuration’s identityProviders list. Since this is the only IdP configured in our setup, it is at index 0. If you have multiple identity providers (for example, an htpasswd provider before the LDAP provider), the index will change accordingly and you should adjust the path to match.

You can then run the command below to test the connection. Let’s list the groups in our OU:

ldapsearch -x -H ldaps://dc01.kifarunix.com:636 \
        -D "cn=read-only,ou=ServiceAccounts,dc=kifarunix,dc=com" \
        -w `cat /var/config/user/idp/0/secret/v4-0-config-user-idp-0-bind-password/bindPassword` \
        -b "ou=accessgroups,dc=kifarunix,dc=com" \
        -o "TLS_CACERT=/var/config/user/idp/0/configMap/v4-0-config-user-idp-0-ca/ca.crt" \
        dn \
        -LLL

Sample output;

dn: OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-Admins,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-Infra,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-Developers,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-CyberSec,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-ViewOnly,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=ERP-Admins,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=DBA-Admins,OU=AccessGroups,DC=kifarunix,DC=com

dn: CN=OCP-All,OU=AccessGroups,DC=kifarunix,DC=com

This confirms that the AD LDAPS configuration is functional inside OpenShift.

Exit the pod when done.

exit

Test AD User Login via OpenShift Console and CLI

After validating the Bind DN connection, test user authentication to confirm the LDAP Identity Provider (IdP) is working as expected.

OpenShift Web Console:

  1. If you’re already logged into the OpenShift web console, log out first. Otherwise, open the console URL in a private/incognito browser window to avoid session interference.
  2. On the login screen, you should see a list of configured identity providers.
    Integrate OpenShift with Active Directory for Authentication
  3. Select your Active Directory / LDAP IdP (e.g., win-ad-idp).
    Integrate OpenShift with Active Directory for Authentication
  4. Enter your AD user credentials and try logging in.

If successful, you’ll be redirected to the OpenShift dashboard with the user session initialized.

ad user login ocp dashboard

To test login from the CLI obtain the API address:

oc whoami --show-server

Sample API:

https://api.ocp.kifarunix.com:6443

Then login as AD user:

oc login -u <your-ad-username> https://<your-cluster-api>:6443

For example:

oc login -u b.colly https://api.ocp.kifarunix.com:6443

When prompted, provide the AD user password.

Console URL: https://api.ocp.kifarunix.com:6443/console
Authentication required for https://api.ocp.kifarunix.com:6443 (openshift)
Username: b.colly
Password: 
Login successful.

You don't have any projects. You can try to create a new project, by running

    oc new-project 

kifarunix@ocp-bastion:~/ocp-upi$ oc whoami
b.colly

Step 7: Synchronize AD Groups with OpenShift groups

After confirming that AD authentication is working, the next step is to configure authorization in order to be able to control what authenticated AD users can do in OpenShift.

Rather than assigning permissions individually, you can synchronize Active Directory (AD) groups into OpenShift groups using an LDAPSyncConfig custom resource. This allows you to map AD group memberships to OpenShift roles (e.g., admin, edit, view, or cluster-admin, e.t.c), enabling centralized and scalable access control.

Synchronizing AD Groups with OpenShift groups brings about:

  • Scalability: Managing permissions through AD groups is far more efficient than assigning roles to individual users.
  • Centralized Management: Permissions are controlled through existing AD infrastructure, reducing OpenShift-specific administration.
  • RBAC Integration: Synced groups become OpenShift Group objects, which can be directly bound to cluster or project roles.

OpenShift supports group synchronization from LDAP directories using three common schemas for defining group membership:

  • Active Directory: Designed for environments where user entries list group membership via the memberOf attribute. OpenShift infers group associations by querying users, without querying group objects directly. This method is ideal when you only need to sync group membership, not group metadata.
  • RFC 2307: Based on traditional UNIX-style LDAP schemas like OpenLDAP, where group entries store user lists using attributes such as member or memberUid. User entries typically do not reference their groups. This schema is well-suited for POSIX-compliant directories and offers fine-grained filtering and control.
  • Augmented Active Directory: A hybrid approach for Active Directory environments that queries both user and group entries. Groups define their members using the member attribute, while users can also be queried for context. This schema supports syncing group metadata and allows more precise targeting of groups and users.

In this setup, we are using RFC 2307 schema because our AD setup uses standard member-based group relationships and supports direct querying of group members. It gives us precise control over group and user queries, making it better suited for our structured OU-based group model (OU=AccessGroups)..

The process of synchronizing Active Directory (AD) groups into OpenShift follows these steps:

  1. Define an LDAPSyncConfig YAML file that describes your AD structure and group query logic.
  2. Perform an initial group synchronization using the oc adm groups sync command.
  3. (Optional) Set up a CronJob to automate and schedule regular group syncs.

Create the LDAP Sync Configuration

Below is our sample configuration. Note that for a one-off sync using the oc adm groups sync command:

  • you must manually type the bind password (bindPassword: “yourbindPassword”) on the YAML
  • specify the path to the CA certificate file (ca: ./ad-ldaps-ca.crt) on the local host where the command is run.

However, for automated syncs (e.g., via a CronJob), the bind password and CA certificate must be accessible within the pod, typically by mounting them from a Kubernetes Secret and ConfigMap.

cat ad-groups-sync-config.yaml
apiVersion: v1
kind: LDAPSyncConfig
url: ldaps://dc01.kifarunix.com:636
bindDN: "CN=read-only,OU=ServiceAccounts,DC=kifarunix,DC=com"
bindPassword: "yourbindPassword"
ca: ./ad-ldaps-ca.crt
insecure: false
groupUIDNameMapping: {}
rfc2307:
  groupsQuery:
    baseDN: OU=AccessGroups,DC=kifarunix,DC=com
    scope: sub
    derefAliases: never
    filter: (&(objectClass=group)(cn=OCP-*)(!(cn=OCP-All)))
    pageSize: 0
  groupUIDAttribute: dn
  groupNameAttributes: [ cn ]
  groupMembershipAttributes: [ member ]
  usersQuery:
    baseDN: DC=kifarunix,DC=com
    scope: sub
    derefAliases: never
    pageSize: 0
  userUIDAttribute: dn
  userNameAttributes: [ sAMAccountName ]
  tolerateMemberNotFoundErrors: true
  tolerateMemberOutOfScopeErrors: true

Before you can proceed, log back into OpenShift as an admin user.

oc login -u kubeadmin

Run Initial One-off AD Groups Sync to OpenShift

To perform a one-time LDAP group sync, you can run the following command from a machine with oc access (e.g., a bastion host):

Dry run:

oc adm groups sync --sync-config=./ad-groups-sync-config.yaml

This command reads your LDAP configuration from the ad-sync-config.yaml file and prints the specified AD groups into OpenShift to stdout.

To write the groups to OpenShift, confirm the task:

oc adm groups sync --sync-config=./ad-groups-sync-config.yaml --confirm

Sample command output for my setup:

group/OCP-Admins
group/OCP-CyberSec
group/OCP-Developers
group/OCP-Infra
group/OCP-ViewOnly

If you want some level of verbosity, add the option, –loglevel=8.

You can also utilize the whitelist or blacklist option to restrict which groups to sync. Refer to oc adm groups sync –help.

You can verify the imported groups with:

oc get groups
NAME             USERS
OCP-Admins       b.colly
OCP-CyberSec     r.roe
OCP-Developers   a.smith
OCP-Infra        
OCP-ViewOnly

Get group details on OpenShift:

oc describe group OCP-Admins

See result:

Name:		OCP-Admins
Created:	2 minutes ago
Labels:		openshift.io/ldap.host=dc01.kifarunix.com
Annotations:	openshift.io/ldap.sync-time=2025-08-22T15:30:03Z
		openshift.io/ldap.uid=CN=OCP-Admins,OU=AccessGroups,DC=kifarunix,DC=com
		openshift.io/ldap.url=dc01.kifarunix.com:636
Users:		b.colly

Note, if for some reasons you need to desync AD groups from OpenShift, you can simply delete the synced groups using:

oc delete group <group-name>

This removes them from OpenShift without affecting the original groups in Active Directory.

Also check:

oc adm prune groups --help

Set Up Automatic AD Group Sync in OpenShift Using a CronJob

You can automate synchronization of AD groups into OpenShift by scheduling a periodic CronJob. This is useful for keeping your OpenShift RBAC in sync with changes in Active Directory.

To proceed, ensure:

  • You are logged into the cluster as a cluster admin.
  • An LDAP Identity Provider (IDP). This is already configured above.
  • You have created:
    • A secret containing the AD bind credentials.
    • A ConfigMap containing the AD CA certificate.

Hence create a new project for the AD Groups sync CronJob. You can use any suitable name for your project:

oc new-project ad-group-sync

Remember the bind password secret and CA certificate ConfigMap we created before:

oc get secret,cm -n openshift-config
NAME                                             TYPE                             DATA   AGE
secret/ad-binddn-secret                          Opaque                           1      45h
...

NAME                                         DATA   AGE
configmap/ad-ldaps-ca-cert                   1      46h
...

Copy them from openshift-config to your new project above.

oc get secret ad-binddn-secret -n openshift-config -o yaml | \
sed 's/namespace: openshift-config/namespace: ad-group-sync/' | oc apply -f -
oc get configmap ad-ldaps-ca-cert -n openshift-config -o yaml | \
sed 's/namespace: openshift-config/namespace: ad-group-sync/' | oc apply -f -

Confirm they there on your project:

oc get secret,cm
NAME                      TYPE     DATA   AGE
secret/ad-binddn-secret   Opaque   1      65s

NAME                                 DATA   AGE
configmap/ad-ldaps-ca-cert           1      6s
configmap/kube-root-ca.crt           1      5m59s
configmap/openshift-service-ca.crt   1      5m59s

Next, create a service account that will be used to grant the CronJob pods the appropriate permissions to perform the group sync operation.

oc create sa ad-group-syncer

Next, create a ClusterRole that defines the permissions required for the CronJob pods to perform group synchronization operations. The required permissions include the ability to get, list, create, and update OpenShift group resources;

oc create clusterrole ad-group-syncer --verb=get,list,create,update --resource=groups.user.openshift.io

Create a ClusterRoleBinding that links the previously created ClusterRole to the ServiceAccount, granting the CronJob pods the necessary permissions.

oc create clusterrolebinding ad-group-syncer --clusterrole=ad-group-syncer --serviceaccount=ad-group-sync:ad-group-syncer

Now, you have to create the LDAPSyncConfig as a configmap. As such, edit the LDAPSyncConfig configuration above and update the bindPassword and ca fields to point to the appropriate file paths where the bind password secret and CA certificate will be mounted. We will configure the sync CronJob to mount the corresponding Kubernetes Secret and ConfigMap into the container at the specified paths. This ensures that the LDAP bind credentials and TLS certificate are securely and consistently available during each sync operation.

Here is our updated LDAPSyncConfig file:

cat ad-groups-sync-config.yaml
apiVersion: v1
kind: LDAPSyncConfig
url: ldaps://dc01.kifarunix.com:636
bindDN: "CN=read-only,OU=ServiceAccounts,DC=kifarunix,DC=com"
bindPassword:
  file: "/etc/secrets/bindPassword"
ca: /etc/ldap-ca/ca.crt
insecure: false
groupUIDNameMapping: {}
rfc2307:
  groupsQuery:
    baseDN: OU=AccessGroups,DC=kifarunix,DC=com
    scope: sub
    derefAliases: never
    filter: (&(objectClass=group)(cn=OCP-*)(!(cn=OCP-All)))
    pageSize: 0
  groupUIDAttribute: dn
  groupNameAttributes: [ cn ]
  groupMembershipAttributes: [ member ]
  usersQuery:
    baseDN: DC=kifarunix,DC=com
    scope: sub
    derefAliases: never
    pageSize: 0
  userUIDAttribute: dn
  userNameAttributes: [ sAMAccountName ]
  tolerateMemberNotFoundErrors: true
  tolerateMemberOutOfScopeErrors: true

Then create a configmap;

oc create cm ad-groups-sync-config --from-file=ad-groups-sync-config.yaml

And finally, create the CronJob. Below is a manifest file we will use to create our cronjob.

cat ad-group-sync-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: ad-group-syncer
  namespace: ad-group-sync
spec:
  schedule: "*/30 * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      backoffLimit: 0
      ttlSecondsAfterFinished: 1800
      template:
        spec:
          serviceAccountName: ad-group-syncer
          containers:
          - name: ad-group-sync
            image: registry.redhat.io/openshift4/ose-cli:latest
            command:
            - "/bin/bash"
            - "-c"
            - |
              oc adm groups sync --sync-config=/etc/config/ad-groups-sync-config.yaml --confirm
            volumeMounts:
            - name: ad-sync-config
              mountPath: /etc/config
            - name: ad-bind-password
              mountPath: /etc/secrets
            - name: ad-ca-cert
              mountPath: /etc/ldap-ca
          volumes:
          - name: ad-sync-config
            configMap:
              name: ad-groups-sync-config
          - name: ad-ca-cert
            configMap:
              name: ad-ldaps-ca-cert              
          - name: ad-bind-password
            secret:
              secretName: ad-binddn-secret
          restartPolicy: Never
          terminationGracePeriodSeconds: 30
          activeDeadlineSeconds: 500
          dnsPolicy: "ClusterFirst"

This CronJob runs the oc adm groups sync command every 30 minutes to synchronize AD groups into OpenShift. It mounts the LDAP sync config file, bind password secret, and CA certificate into the container, and uses a dedicated service account (ad-group-syncer) with the required ClusterRole permissions to manage OpenShift group objects.

The apply the cronjob yaml to create it.

oc apply -f ad-group-sync-cronjob.yaml

Confirm the job is created:

 oc get cronjobs
NAME              SCHEDULE       TIMEZONE   SUSPEND   ACTIVE   LAST SCHEDULE   AGE
ad-group-syncer   */30 * * * *        False     0                  41s

NB: We reduced the schedule time to every two minutes to allow us verify if all is working as expected without having to wait for 30 mins.

So, by now, the cronjob should have already ran.

oc get jobs
NAME                       STATUS     COMPLETIONS   DURATION   AGE
ad-group-syncer-29264618   Complete   1/1           6s         4m49s
ad-group-syncer-29264620   Complete   1/1           6s         2m49s
ad-group-syncer-29264622   Complete   1/1           5s         49s

Check the status of the latest Job(s):

oc describe job ad-group-syncer-29264622
Name:                        ad-group-syncer-29264622
Namespace:                   ad-group-sync
Selector:                    batch.kubernetes.io/controller-uid=039ab3ce-50db-4407-8e98-cf7f5012ba5d
Labels:                      batch.kubernetes.io/controller-uid=039ab3ce-50db-4407-8e98-cf7f5012ba5d
                             batch.kubernetes.io/job-name=ad-group-syncer-29264622
                             controller-uid=039ab3ce-50db-4407-8e98-cf7f5012ba5d
                             job-name=ad-group-syncer-29264622
Annotations:                 batch.kubernetes.io/cronjob-scheduled-timestamp: 2025-08-22T15:42:00Z
Controlled By:               CronJob/ad-group-syncer
Parallelism:                 1
Completions:                 1
Completion Mode:             NonIndexed
Suspend:                     false
Backoff Limit:               0
TTL Seconds After Finished:  1800
Start Time:                  Fri, 22 Aug 2025 15:42:00 +0000
Completed At:                Fri, 22 Aug 2025 15:42:05 +0000
Duration:                    5s
Pods Statuses:               0 Active (0 Ready) / 1 Succeeded / 0 Failed
Pod Template:
  Labels:           batch.kubernetes.io/controller-uid=039ab3ce-50db-4407-8e98-cf7f5012ba5d
                    batch.kubernetes.io/job-name=ad-group-syncer-29264622
                    controller-uid=039ab3ce-50db-4407-8e98-cf7f5012ba5d
                    job-name=ad-group-syncer-29264622
  Service Account:  ad-group-syncer
  Containers:
   ad-group-sync:
    Image:      registry.redhat.io/openshift4/ose-cli:latest
    Port:       
    Host Port:  
    Command:
      /bin/bash
      -c
      oc adm groups sync --sync-config=/etc/config/ad-groups-sync-config.yaml --confirm
      
    Environment:  
    Mounts:
      /etc/config from ad-sync-config (rw)
      /etc/ldap-ca from ad-ca-cert (rw)
      /etc/secrets from ad-bind-password (rw)
  Volumes:
   ad-sync-config:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      ad-groups-sync-config
    Optional:  false
   ad-ca-cert:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      ad-ldaps-ca-cert
    Optional:  false
   ad-bind-password:
    Type:          Secret (a volume populated by a Secret)
    SecretName:    ad-binddn-secret
    Optional:      false
  Node-Selectors:  
  Tolerations:     
Events:
  Type    Reason            Age    From            Message
  ----    ------            ----   ----            -------
  Normal  SuccessfulCreate  3m19s  job-controller  Created pod: ad-group-syncer-29264622-jdrq8
  Normal  Completed         3m14s  job-controller  Job completed

The output shows the Job completed successfully:

  • Pods Status: 1 Succeeded / 0 Failed means the Pod ran and finished without errors.
  • Events: Job completed confirms the Job ran to completion.
  • The Pod named ad-group-syncer-29264622-jdrq8 was created and completed.

Check the Pods created by the Job:

oc get pods -n ad-group-sync --selector=job-name=<job-name>

View the logs of the Pod to confirm the group sync operation:

oc logs <pod-name> -n ad-group-sync

Look for success messages or errors from the oc adm groups sync command.

(Optional) Watch pod status in real-time:

oc get pods -n ad-group-sync -w

Step 8: Configure Authorization with RBAC

Once users and groups are synced, use RBAC to explicitly assign permissions.

OpenShift follows a default-deny model. For example, I am currently logged as AD user, Bob Colly (b.colly):

oc whoami
b.colly

If try to run some command, you may get a Forbidden message.

oc get groups
Error from server (Forbidden): groups.user.openshift.io is forbidden: User "b.colly" cannot list resource "groups" in API group "user.openshift.io" at the cluster scope

Hence, you must bind roles directly to users or groups to grant access. OpenShift uses the usual Kubernetes RBAC components:

  • RoleBindings: Assign Roles to users/groups within projects.
  • ClusterRoles: Define permissions across the entire cluster.
  • Roles: Define permissions within specific projects/namespaces.
  • ClusterRoleBindings: Assign ClusterRoles to users/groups cluster-wide

So, to begin, login as a cluster admin:

oc whoami
kube:admin

Then, you can now map groups to specific rols. For example, let’s assign the OCP-Admins group some admin rights on the cluster.

oc adm policy add-cluster-role-to-group cluster-admin OCP-Admins

And now, any user who is a member of the OCP-Admins group will be granted cluster-admin privileges across the OpenShift cluster.

As an admin user, you can now verify access for the members of the group. For example, b.colly is a member of OCP-Admins group. Let’s check their permissions:

oc auth can-i '*' '*' --all-namespaces --as="b.colly" --as-group=OCP-Admins

Since user via the OCP-Admins group is in cluster-admin role, this should return yes for all queries.

Step 9: Validate Active Directory User Permissions

After syncing your AD groups and assigning roles, it’s important to verify that users have the expected access in OpenShift. This can be done via the web console or CLI like we did above.

Using the OpenShift Web Console:

  • Log out of the console if you’re currently logged in.
  • Log in using the credentials of an AD user (e.g., b.colly) who belongs to a synced group with permissions (e.g., OCP-Admins).
  • If the user has cluster-level permissions (e.g., cluster-admin), they will see options like:
    • Cluster Settings
    • Cluster Operators
    • Custom Resource Definitions
  • If the user does not have sufficient permissions, these options will be hidden.

Validate AD User Permissions via CLI:

  • Log in to the CLI as the AD user:
    oc login -u r.roe
  • Run a command to check permissions, for example, list groups:
    oc get groups
  • If the user is an admin, the command will return the list of groups.
  • If the user is not an admin, you will see a “forbidden” error message like:
    Error from server (Forbidden): groups.user.openshift.io is forbidden: User "r.roe" cannot list resource "groups" in API group "user.openshift.io" at the cluster scope

Step 10: Create Custom Roles if Needed

If the default roles (such as admin, edit, or view) don’t meet your requirements, you can create a custom role.

Example custom role YAML:

custom-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: custom-role
  namespace: my-project
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]

Apply the role:

oc apply -f custom-role.yaml

Bind the custom role to a group in the specific namespace:

oc adm policy add-role-to-group custom-role ocp-viewonly -n my-project

Read more on:

As a best practice, ensure:

  • Least Privilege: Start with view and escalate as needed.
  • Group-Based: Prefer binding to groups over individual users for scalability.
  • Auditing: Regularly review roles and cluster roles.
  • Avoid Defaults: Don’t modify built-in roles; create new ones.
  • Testing: After changes, log in as an AD user and test access (e.g., oc get pods).

Considerations for Removing the kubeadmin Account

After integrating OpenShift with Active Directory (AD), you may want to remove the default kubeadmin account for security reasons. However, be cautious:

  • If AD becomes unreachable, and kubeadmin is removed, you could be locked out of the cluster.
  • Ensure AD is highly available before removing kubeadmin (e.g., multiple LDAP endpoints, DNS failover).
  • Consider adding a fallback identity provider (e.g., HTPasswd) with a local admin account for emergencies.

Do not delete the kubeadmin credentials until you have tested HA for AD authentication and/or implemented a fallback identity provider.

Conclusion

By integrating OpenShift with Active Directory and properly configuring authentication, group synchronization, and RBAC, you enable centralized, secure access management for your cluster. Ensure high availability for AD services and retain a fallback admin method before removing the kubeadmin account to avoid access disruption

SUPPORT US VIA A VIRTUAL CUP OF COFFEE

We're passionate about sharing our knowledge and experiences with you through our blog. If you appreciate our efforts, consider buying us a virtual coffee. Your support keeps us motivated and enables us to continually improve, ensuring that we can provide you with the best content possible. Thank you for being a coffee-fueled champion of our work!

Photo of author
Kifarunix
DevOps Engineer and Linux Specialist with deep expertise in RHEL, Debian, SUSE, Ubuntu, FreeBSD... Passionate about open-source technologies, I specialize in Kubernetes, Docker, OpenShift, Ansible automation, and Red Hat Satellite. With extensive experience in Linux system administration, infrastructure optimization, information security, and automation, I design and deploy secure, scalable solutions for complex environments. Leveraging tools like Terraform and CI/CD pipelines, I ensure seamless integration and delivery while enhancing operational efficiency across Linux-based infrastructures.

Leave a Comment