Skip to content

Openshift - LDAP Auth

   

I’m posting my experience with configuring LDAP and Active Directory Authentication since it took to me a few hours to understand how it works on Openshift / OKD and how I may debug it. First things first, it’s best to use a Standalone Master or even Minishift to do all the steps and get to a working config you may use in your HA Cluster. Having it said, let’s get hands dirty.

Disclaimer

This guide is based on version 3.11 of OKD, the Community version of Openshift, and while it may works on both distributions and early versions, I can’t garantee it.

What you’ll need:

1 - A working regular user on your LDAP or AD which doesn’t need to have any Admin rights, and it’s best to use a dedicated one withouth password expiration. For the purpose of this setup, let’s call it openshift_user.

2 - Your LDAP or AD server endpoints. Keep in mind that Openshift at least on version 3.11 doesn’t support multiple servers so you’ll have to choose one (if you have more than one servers), or:

2.1 - Use a LDAP Fallback Strategy (http://openshift……)

2.2 - Connect without TLS which is not aconselhado advised.

3 - Your LDAP or AD CA (Certificate Authority) in case you use an encrypted connection, and you should

How to debug

I’ll recommend you to increase the verbosity of master-api containter logs. If you have setup your environment through RPM you change the following line on /etc/origin/master/master.env:

DEBUG_LOGLEVEL=4

Note that default value is 2

LDAP Certificate

If you have a SSL enabled LDAP or Active directory you must copy your CA file /etc/origin/master/ folder. For instance let’s call it freeipa_ca.crt:

$ sudo cp freeipa_ca.crt /etc/origin/master/

A working config example

Than you can finally edit your /etc/origin/master/master-config.yaml and add your LDAP settings. You’ll need to add your settings after the identityProviders key. Let’s have a look to a working configuration:

  identityProviders:
  - challenge: true
    login: true
    mappingMethod: lookup
    name: allow_all
    provider:
      apiVersion: v1
      kind: AllowAllPasswordIdentityProvider
  - name: freeipa
    challenge: true
    login: true
    mappingMethod: claim
    provider:
      apiVersion: v1
      kind: LDAPPasswordIdentityProvider
      attributes:
        id:
        - dn
        email:
        - mail
        name:
        - cn
        preferredUsername:
        - uid
      bindDN: "uid=openshift_user,cn=users,cn=accounts,dc=example,dc=com"
      bindPassword: "openshift_password"
      insecure: false
      ca: freeipa_ca.crt
      url: "ldap://server.example.com/cn=users,cn=accounts,dc=example,dc=com?uid"

Default users

The first thing you’ll notice is that if you haven’t setup anything on your Openshift deployment, you’ll have an default AllowAllPasswordIdentityProvider identity provider, which permits you to login as any user with any password. This provider is called allow_all and you can check out that the standard setup provides some users.

$ oc get users
admin             1234abcd-87f3-21e9-d610-0050269ae124                     allow_all:admin
developer         4567efab-8669-13e9-d610-00595795ec24                     allow_all:developer
sysadmin          8901cdef-11e9-8d4f-9fe7-00405695f2d6                     allow_all:sysadmin

You can also find some information with the oc get identity command:

$ oc get identity
NAME                IDP NAME        IDP USER NAME       USER NAME       USER UID
allow_all:admin     allow_all       admin               admin           1234abcd-87f3-21e9-d610-0050269ae124

The mappingMethod defined to claim means that any new login will be automatically provisioned, which doesnt means itll gain any default right. On Openshift every new user has no access but may create new Projects. You can change this behavior latter.

Before we start to write our LDAP provider config, it’s best to check the credentials and dn with the help of ldapsearch utility.

$ ldapsearch -h server.example.com -b dc=example,dc=com -v -D "uid=openshift_user,cn=users,cn=accounts,dc=example,dc=com" -W "uid=myusername"

ldap_initialize( ldap://server.example.com )
Enter LDAP Password: 
filter: uid=myusername
requesting: All userApplication attributes
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: uid=myusername
# requesting: ALL
#

# myusername, users, compat, ipa.imusicacorp.com
dn: uid=myusername,cn=users,cn=compat,dc=example,dc=com
objectClass: posixAccount
...

In this case we’ve used the openshift_user to check our own login myusername through our LDAP directory. If this command doesn’t work please make sure you have a working credential to authenticate against your server and/or an valid user to look for thorugh your directory. For a standard FreeIPA setup the DN cn=users,cn=accounts,dc=example,dc=com is the default. Please replace dc=example,dc=com with your domain name.

Parameters explained

Going forward through the LDAP provider setup, we’ll have to define some fields explained right below. You can always get more detailed information on https://docs.okd.io/3.11/install_config/configuring_authentication.html

  • kind: LDAPPasswordIdentityProvider - Is the provider used with LDAP or Active Directory
  • attributes: - Is a map to your OpenLDAP solution fields. You can check all of then over the ldapsearch output, but keep in mind that: ** id: dn - List of attributes to use as an unique identity to users. Can be dn both on OpenLDAP or AD ** email: mail - A list of attributes to use as the email address, could be mail on FreeIPA and most OpenLDAP setups ** name: cn - A list of attributes to use as the display name. Normally is cn which stands to Common Name ** preferredUsername - List of attributes to use as preferred user name when provisioning a user for this identity. Could be uid on FreeIPA and most OpenLDAP setups
  • bindDN - The dn used to bind during the search phase. For instance, “uid=openshift_user,cn=users,cn=accounts,dc=example,dc=com”
  • bindPassword - Password used to bind during the search phase
  • insecure: false - If false, a TLS connection is made to the LDAP server and ca is needed. If true, a plain text connection is made to the LDAP server.
  • url - An RFC 2255 connection string used to connect to your LDAP server and search parameters, for instance, “ldap://server.example.com/cn=users,cn=accounts,dc=example,dc=com?uid”

If you are connecting to an Active Directory server, some values are slightly differents and we’ll figure out below:

  • kind: LDAPPasswordIdentityProvider - Is the provider used with LDAP or Active Directory
  • attributes: - Is a map to your OpenLDAP solution fields. You can check all of then over the ldapsearch output, but keep in mind that: ** id: dn - List of attributes to use as an unique identity to users. Can be dn both on OpenLDAP or AD ** email: mail - An attribute to use as the email address, could be userPrincipalName on AD ** name: cn - A list of attributes to use as the display name. Normally is cn which stands to Common Name ** preferredUsername - List of attributes to use as preferred user name when provisioning a user for this identity. Should be sAMAccountName on AD
  • bindDN - The dn used to bind during the search phase. For instance, “CN=Openshift User,OU=users,dc=example,dc=com”
  • bindPassword - Password used to bind during the search phase
  • ca - Certificate bundle used to validate the LDAP server. The filename is relative to the /etc/origin/master/ path.
  • insecure: false - If false, a TLS connection is made to the LDAP server and ca is needed. If true, a plain text connection is made to the LDAP server.
  • url - An RFC 2255 connection string used to connect to your LDAP server and search parameters, for instance, “ldap://server.example.com/cn=Users,dc=example,dc=com?samAccountName”

Restart container

$ sudo /usr/local/bin/master-restart api

Listen to logs:

$ oc logs -n kube-system master-api-your-master.example.com --tail 10 -f

If your master-api container doesn`t start you may try to get the last logs through master-logs command:

$ sudo /usr/local/bin/master-logs api api

If everything is ok but master-api container still refuse to get running you may try do reboot your node, or delete the container if you have a HA Cluster. I’m not sure if it’s safe to delete this container on a single node setup.

$ oc delete pod master-api-your-master.example.com -n kube-system

As long as your master-api container is running

$ oc get pods --all-namespaces | grep master-api`
...
kube-system                         master-api-your-master.example.com            2         2h
...

Try to login to OpenShift and check it out if it works.

$ oc login https://console-okd.example.com -u myusername
Authentication required for https://console-okd.example.com:443 (openshift)
Username: myusername
Password: 
Login successful.

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

    oc new-project <projectname>

If you have a HA Cluster you may try to login on a specific master before you replicate the setup over the other hosts.

oc login https://192.168.0.101 -u myusername --insecure-skip-tls-verify=true

If everything is fine you should see some lines like these on your master-api logs:

  • For an OpenLDAP server:
I0619 23:59:01.043254       1 basicauth.go:51] Login with provider "allow_all" failed for login "myusername"
I0619 23:59:01.069449       1 ldap.go:122] searching for (&(objectClass=*)(uid=myusername))
I0619 23:59:01.081760       1 ldap.go:139] found dn="uid=myusername,cn=users,cn=accounts,dc=example,dc=com" for (&(objectClass=*)(uid=myusername))
I0619 23:59:01.096297       1 wrap.go:42] GET /apis/user.openshift.io/v1/identities/freeipa:uid=myusername,cn=users,cn=accounts,dc=exmaple,dc=com: (2.029694ms) 404 [[openshift/v1.11.0+d4cacc0 (linux/amd64) kubernetes/d4cacc0] 127.0.0.1:34354]
I0619 23:59:01.098495       1 wrap.go:42] GET /apis/user.openshift.io/v1/users/myusername: (1.668434ms) 404 [[openshift/v1.11.0+d4cacc0 (linux/amd64) kubernetes/d4cacc0] 127.0.0.1:34354]
I0619 23:59:01.108249       1 ldap.go:67] identitymapper: got userIdentityMapping: &user.DefaultInfo{Name:"myusername", UID:"5aec33fe-9307-11e9-9fca-00505695e124", Groups:[]string(nil), Extra:map[string][]string(nil)}
I0619 23:59:01.108266       1 basicauth.go:54] Login with provider "freeipa" succeeded for login "myusername": &user.DefaultInfo{Name:"myusername", UID:"5aec33fe-9307-11e9-9fca-00505695e124", Groups:[]string(nil), Extra:map[string][]string(nil)}
I0619 23:59:01.108284       1 authenticator.go:54] OAuth authentication succeeded: &user.DefaultInfo{Name:"myusername", UID:"5aec33fe-9307-11e9-9fca-00505695e124", Groups:[]string(nil), Extra:map[string][]string(nil)}
I0619 23:59:01.116583       1 wrap.go:42] GET /apis/oauth.openshift.io/v1/oauthclientauthorizations/myusername:openshift-challenging-client: (8.114051ms) 404 [[openshift/v1.11.0+d4cacc0 (linux/amd64) kubernetes/d4cacc0] 127.0.0.1:34354]
I0619 23:59:01.156035       1 wrap.go:42] GET /apis/user.openshift.io/v1/users/myusername: (1.769995ms) 200 [[openshift/v1.11.0+d4cacc0 (linux/amd64) kubernetes/d4cacc0] 192.168.0.1:60816]
  • For an Active Directory server:
I0620 00:18:49.513445       1 ldap.go:122] searching for (&(objectClass=*)(samaccountname=myusername))
I0620 00:18:49.514174       1 ldap.go:139] found dn="CN=My Username,OU=Users,DC=example,DC=com" for (&(objectClass=*)(samaccountname=myusername))
I0620 00:18:49.520484       1 wrap.go:42] GET /apis/user.openshift.io/v1/users/myusername: (1.670994ms) 404 [[openshift/v1.11.0+d4cacc0 (linux/amd64) kubernetes/d4cacc0] 127.0.0.1:43366]
I0620 00:18:49.530471       1 ldap.go:67] identitymapper: got userIdentityMapping: &user.DefaultInfo{Name:"myusername", UID:"af56f4cf-32ba-1fe9-1a3e-0c5d5e95e124", Groups:[]string(nil), Extra:map[string][]string(nil)}
I0620 00:18:49.530486       1 basicauth.go:54] Login with provider "activedirectory" succeeded for login "myusername": &user.DefaultInfo{Name:"myusername", UID:"af56f4cf-32ba-1fe9-1a3e-0c5d5e95e124", Groups:[]string(nil), Extra:map[string][]string(nil)}
I0620 00:18:49.530529       1 authenticator.go:54] OAuth authentication succeeded: &user.DefaultInfo{Name:"myusername", UID:"af56f4cf-32ba-1fe9-1a3e-0c5d5e95e124", Groups:[]string(nil), Extra:map[string][]string(nil)}
I0620 00:18:49.532735       1 wrap.go:42] GET /apis/oauth.openshift.io/v1/oauthclientauthorizations/myusername:openshift-challenging-client: (1.970192ms) 404 [[openshift/v1.11.0+d4cacc0 (linux/amd64) kubernetes/d4cacc0] 127.0.0.1:43366]
I0620 00:18:49.590815       1 wrap.go:42] GET /apis/user.openshift.io/v1/users/myusername: (1.714394ms) 200 [[openshift/v1.11.0+d4cacc0 (linux/amd64) kubernetes/d4cacc0] 192.168.0.101:41592]

Sometimes during our tests, user get created over the allow_all provider or even with wrong identity settings. This specially happens when working on a HA Cluster and when you haven’t removed or disabled allow_all provider. In this case it’s good to use oc get users and/or oc get identity to check if the user has been created and if necessary, to delete it.

$ oc delete user myusername
user.user.openshift.io "myusername" deleted

$ oc delete identity freeipa:uid=myusername,cn=users,cn=accounts,dc=example,dc=com
identity.user.openshift.io "freeipa:uid=myusername,cn=users,cn=accounts,dc=example,dc=com" deleted

And, that`s it. If everything is fine you can now replicate the setup over the other hosts of your HA Cluster.

Note that if you have a HA Cluster you have to reproduce the steps above over each Master host, but before you do it, try to login over the host if just changed the config.

$ sudo cat /etc/origin/master/master-config.yaml | ssh your-master02.example.com "sudo tee /etc/origin/master/master-config.yaml"
$ ssh your-master02.example.com "sudo /usr/local/bin/master-restart api"

Wait until the master api is up and running and proceed to your other servers.

comments powered by Disqus