Skip to content

Instantly share code, notes, and snippets.

@acsulli
Created July 1, 2021 19:59
Show Gist options
  • Save acsulli/5acdb1de102b4771553bb9e4b458cb21 to your computer and use it in GitHub Desktop.
Save acsulli/5acdb1de102b4771553bb9e4b458cb21 to your computer and use it in GitHub Desktop.
Supporting information for the OpenShift.tv live stream here: https://www.youtube.com/watch?v=RG6xt2q72nw

Configuring Active Directory authentication with OpenShift 4

  1. Understand AD LDAP structure and naming. Read the docs on the components

    Refer to the OpenShift docs for the LDAP identity provider and LDAP group syncing.

  2. Create the OAuth config

    # create a secret for the bindDN user password
    oc create secret generic ldap-bind-secret \
      --from-literal=bindPassword=<secret> \
      -n openshift-config
    
    # create the OAuth config file, you may want to update your existing or use 
    # the GUI if you have more than one auth provider
    cat << EOF > ad-oauth.yaml
    apiVersion: config.openshift.io/v1
    kind: OAuth
      name: cluster
    spec:
      identityProviders:
        - ldap:
            attributes:
              email:
                - mail
              id:
                - sAMAccountName
              name:
                - cn
              preferredUsername:
                - sAMAccountName
            bindDN: openshift-sa
            bindPassword:
              name: ldap-bind-secret
            insecure: false
            url: ldap://lab.lan/OU=Domain Users,DC=lab,DC=lan?sAMAccountName?sub?(&(objectClass=user)(|(memberOf:1.2.840.113556.1.4.1941:=CN=OpenShift Admins,OU=Groups,OU=Domain Users,DC=lab,DC=lan)(memberOf:1.2.840.113556.1.4.1941:=CN=OpenShift Users,OU=Groups,OU=Domain Users,DC=lab,DC=lan)))
          mappingMethod: claim
          name: lab.lan
          type: LDAP
    EOF

    The memberOf:1.2.840.113556.1.4.1941: bit is important because we're wanting to allow only users of the specified group - and nested groups - to be allowed to authenticate. The basedn is very broad, OU=Domain Users,DC=lab,DC=lan, so that all users are accounted for, even if they're spread across many OUs.

    Also, I'm not using LDAPS here because it's a lab and I don't have it configured. You'll probably want to use it.

  3. Apply the config, oc apply -f ad-oauth.yaml, wait for the authentication cluster operator to update (oc get co).

    At this point, we can log into the cluster using Active Directory credentials. Users will be assinged the default authenticated role and whatever permissions are associated with it.

    OpenShift isn't aware of the user(s) until they log in for the first time, so if you were to check oc get user immediately, it would not reflect any AD users. Once you log in with the user account, it will show in the list.

Basic RBAC

With the above authentication configuration in place, we also want to configure authorization so that users are allowed - or not, as the case may be - to access resources.

  1. Configure group syncing

    OpenShift caches the groups and group membership, which means that we need to configure group syncing and pruning to ensure that users are able to (or not, as the case may be) connect as their group memebership in Active Directory is updated.

    Importantly, we're using nested groups for membership, which means that we need to create an allow list and configure the sync config's augmentedActiveDirectory.groupsQuery with some specific options, see the docs here for more info.

    # create the group sync config file
    # the groupUIDNameMapping is added to avoid spaces in the group names
    cat << EOF > ldap-sync.yaml
    kind: LDAPSyncConfig
    apiVersion: v1
    url: ldap://lab.lan
    bindDN: openshift-sa
    bindPassword: '************'
    insecure: false
    groupUIDNameMapping:
      "CN=OpenShift Users,OU=Groups,OU=Domain Users,DC=lab,DC=lan": openshift-users
      "CN=OpenShift Admins,OU=Groups,OU=Domain Users,DC=lab,DC=lan": openshift-admins
    augmentedActiveDirectory:
      groupsQuery:
        derefAliases: never
        pageSize: 0
      groupUIDAttribute: dn
      groupNameAttributes: [ cn ]
      usersQuery:
        baseDN: "OU=Domain Users,DC=lab,DC=lan"
        scope: sub
        derefAliases: never
        filter: (objectclass=person)
        pageSize: 0
      userNameAttributes: [ sAMAccountName ]
      groupMembershipAttributes: [ "memberOf:1.2.840.113556.1.4.1941:" ]
    EOF
    
    # since we're using nested groups, we'll need an allow list as well
    cat << EOF > group-allowlist.txt
    CN=OpenShift Users,OU=Groups,OU=Domain Users,DC=lab,DC=lan
    CN=OpenShift Admins,OU=Groups,OU=Domain Users,DC=lab,DC=lan
    EOF
    
    # do a manual sync, leave off the --confirm if you want to check the result
    # without creating the groups in OpenShift
    oc adm groups sync \
     --whitelist=group-allowlist.txt \
     --sync-config=ldap-sync.yaml \
     --confirm
    
    # check the groups are as expected
    oc get group

    Groups, and their membership, need to be kept in sync with Active Directory. Arguably the easiest way to do this is via the Group Sync Operator, or you can use a CronJob, see below for an example. Creating a CronJob for pruning is also recommended.

  2. Create Roles and ClusterRoles as needed

    The default roles are explained here.

  3. Assign Roles and ClusterRoles to users and groups appropriately

    For a namespace scoped Role, use the format oc adm policy add-role-to-user <role> <user> -n <project>, substituting add-role-to-group when using a group.

    For a clsuter scoped ClusterRole, use the format oc adm policy add-cluster-role-to-user <role> <username>, substituting add-cluster-role-to-group when using a group.

    To assign a group with cluster admin privileges, you would use the command

    oc adm policy add-cluster-role-to-group cluster-admin openshift-admins

Additional info

Group Sync CronJob

Thanks to examples.openshift.pub for this example.

  1. Create a Secret with the relevant files

    oc create secret generic ldap-sync \
     --from-file=ldap-sync.yaml=ldap-sync.yaml \
     --from-file=group-allowlist.txt=group-allowlist.txt
  2. Create a ClusterRole

    oc create clusterrole ldap-group-sync \
     --verb=create,update,patch,delete,get,list \
     --resource=groups.user.openshift.io
  3. Create a Project, ServiceAccount, and ClusterRoleBinding

    oc adm new-project ldap-sync
    oc create sa ldap-sync
    oc adm policy add-cluster-role-to-user ldap-group-sync \
      -z ldap-sync \
      -n ldap-sync
  4. Create the CronJob

    cat << EOF | oc apply -n ldap-sync -f -
    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name: ldap-group-sync
    spec:
      schedule: '@hourly'
      suspend: false
      jobTemplate:
        spec:
          template:
            spec:
              serviceAccountName: ldap-sync
              restartPolicy: Never
              containers:
                - name: oc-cli
                  command:
                    - /bin/oc
                    - adm
                    - groups
                    - sync
                    - --whitelist=/ldap-sync/whitelist.txt
                    - --sync-config=/ldap-sync/ldap-sync.yaml
                    - --confirm
                  image: registry.redhat.io/openshift4/ose-cli
                  imagePullPolicy: Always
                  volumeMounts:
                  - mountPath: /ldap-sync/
                    name: config
                    readOnly: true
              volumes:
              - name: config
                secret:
                  defaultMode: 420
                  secretName: ldap-sync
    EOF
@mdrakiburrahman
Copy link

There is two key typos in this gist that causes the bind and authentication to fail - @acsulli made the same mistake in the YouTube demo https://youtu.be/RG6xt2q72nw?t=3340

image

cat <<EOF | oc apply -f -
apiVersion: config.openshift.io/v1
kind: OAuth
metadata:
  name: cluster
spec:
  identityProviders:
    - ldap:
        attributes:
          email:
            - mail
          id:
            - sAMAccountName
          name:
            - cn
          preferredUsername:
            - sAMAccountName
        bindDN: CN=openshift-sa,OU=Service Accounts,OU=Arc CI,DC=FG,DC=CONTOSO,DC=COM # <------ This should be the full CN
        bindPassword:
          name: ldap-bind-secret
        insecure: true # <------ This should be insecure for demo env
        url: "ldap://fg.contoso.com/OU=Arc CI,DC=FG,DC=CONTOSO,DC=COM?sAMAccountName?sub?(&(objectClass=user)(|(memberOf:1.2.840.113556.1.4.1941:=CN=arcci-admins,OU=Groups,OU=Arc CI,DC=FG,DC=CONTOSO,DC=COM)(memberOf:1.2.840.113556.1.4.1941:=CN=arcci-users,OU=Groups,OU=Arc CI,DC=FG,DC=CONTOSO,DC=COM)))"
      mappingMethod: claim
      name: fg.contoso.com
      type: LDAP
EOF

After that the LDAP login works fine:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment