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 it
ll gain any default right. On Openshift every new user has no access but may create new Projects. You can change this behavior latter.
Testing LDAP Search
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 Directoryattributes:
- 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 bedn
both on OpenLDAP or AD **email: mail
- A list of attributes to use as the email address, could bemail
on FreeIPA and most OpenLDAP setups **name: cn
- A list of attributes to use as the display name. Normally iscn
which stands to Common Name **preferredUsername
- List of attributes to use as preferred user name when provisioning a user for this identity. Could beuid
on FreeIPA and most OpenLDAP setupsbindDN
- Thedn
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 phaseinsecure: false
- Iffalse
, a TLS connection is made to the LDAP server andca
is needed. Iftrue
, 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 Directoryattributes:
- 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 bedn
both on OpenLDAP or AD **email: mail
- An attribute to use as the email address, could beuserPrincipalName
on AD **name: cn
- A list of attributes to use as the display name. Normally iscn
which stands to Common Name **preferredUsername
- List of attributes to use as preferred user name when provisioning a user for this identity. Should besAMAccountName
on ADbindDN
- Thedn
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 phaseca
- Certificate bundle used to validate the LDAP server. The filename is relative to the/etc/origin/master/
path.insecure: false
- Iffalse
, a TLS connection is made to the LDAP server andca
is needed. Iftrue
, 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.