LDAP access to your kubernetes cluster can be confusing to configure.
This guide should assist you with troubleshooting some common issues and misconfigurations. You can use our official documentation here as a base.
However, we can't provide a comprehensive configuration guide as every LDAP environment is different. Your LDAP server might be linux based, or Microsoft ActiveDirectory, or one of the many web based LDAP solutions. Regardless of how your LDAP server is configured you should be able to use this guide to successfully configure LDAP or identify any blocking issues preventing you from doing so.
1. Using ldapsearch
ldapsearch is a command-line utility which we will use to determine what values are available for us to configure, as well as to determine if our ldap accounts have the correct permissions. Install ldapsearch on any computer that has access to both the kubernetes cluster and the ldap server, such as a bastion, bootstrap or worker node.
sudo yum install openldap-clients
LDAP queries we will use in this guide will all use the following format:
ldapsearch -x -W \ -D "" \ -b "" \ -H ldap://SERVERNAME:389 \ ''
The -W flag specifies to prompt the user for a password so that it does not need to be used in plaintext as part of the query
DN or Distinguished Name is the full name of an LDAP object.
Bind DN is the DN (user account) that we use to authenticate with the ldap server. We will use the same Bind DN for all ldap queries.
Base DN specifies the top level for our query. It is important to narrow your search results as much as possible so that you only return information that is relevant to your query.
Some values are case sensitive so please use the exact values your LDAP server queries output as it is difficult to troubleshoot this later.
For our examples, we will be using a publicly available ldap server hosted at formumsys.com. If you want to follow along, the password for the user account used there is simply password.
2. Add an ldap connector account
Dex needs to know what account it should use to query for users and groups, so we must verify this account is valid before any further configuration can be done. In this example, we are using the LDAP account 'read-only-admin', as indicated on the forumsys site. You should contact your LDAP server administrator to find out the account to use in your organization.
The DN for the read-only-admin account is: cn=read-only-admin,dc=example,dc=com
Let's confirm that this account can search for itself. Our search filter will just be the cn (common name) of the account because we currently don't know anything else about it besides its DN.
ldapsearch -x -W -D "cn=read-only-admin,dc=example,dc=com" -b "cn=read-only-admin,dc=example,dc=com" -H ldap://ldap.forumsys.com:389
This search should output the following:
# read-only-admin, example.com
dn: cn=read-only-admin,dc=example,dc=com
sn: Read Only Admin
cn: read-only-admin
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
userPassword:: e1NIQX1XNnBoNU1tNVB6OEdnaVVMYlBnekczN21qOWc9
This tells us all of the properties of this user. Once your query is able to return something like the above, you've confirmed the values needed for your ldap connector account.
Using the example yaml from the documentation as a base, fill in the values so they match the object properties returned by our ldap query. We need to fill in the following values:
password: the password for the ldap server account
host: the ldap server address. By default it will use port 389, you can manually specify the port to override this.
bindDN: in our example it will be cn=read-only-admin,dc=example,dc=com as that is the DN for our ldap connector account.
3. Define a userSearch configuration
userSearch allows ldap to query specific users mapped to individual roleBindings:
userSearch: baseDN: BaseDN to start the search from. filter: Optional filter to apply when searching the directory. username: Username attribute used for comparing user entries. idAttr: String representation of the user. emailAttr: Required. Attribute to map to Email.
To start, lets query a user that we want to enable for full cluster admin access:
ldapsearch -x -W -D "cn=read-only-admin,dc=example,dc=com" -b "dc=example,dc=com" -H ldap://ldap.forumsys.com:389 '(cn=Bernhard Riemann)'
# riemann, example.com
dn: uid=riemann,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Bernhard Riemann
sn: Riemann
uid: riemann
mail: riemann@ldap.forumsys.com
Given the above output, we can fill in the fields that correlate to this user's properties:
userSearch: baseDN: dc=example,dc=com filter: "(objectClass=inetOrgPerson)" username: uid idAttr: uid emailAttr: mail
Note that this user has the 'emailAttr', which is required by the dex ldap connector. If you LDAP server is not configured with email information, you can substitute some other identifying value of the user account, such as the uid.
4. Define a groupSearch configuration
To enable an entire group of users, we need to define a groupSearch configuration that will match the group. The members of the group should match the userSearch configuration we just defined. We need to define the following values to configure the search configuration:
groupSearch: baseDN: BaseDN to start the search from. filter: Optional filter to apply when searching the directory. userAttr: Value that uniquely identifies a user, Must exactly match a value in the Group's member list. groupAttr: Value used to list members of this group. Must exactly match a value in the User's object nameAttr: Represents group name.
The test user we used in our previous example was a member of the mathematicians group. We can query it the same way we would a user:
ldapsearch -x -W -D "cn=read-only-admin,dc=example,dc=com" -b "dc=example,dc=com" -H ldap://ldap.forumsys.com:389 '(cn=mathematicians)'
# mathematicians, example.com
dn: ou=mathematicians,dc=example,dc=com
uniqueMember: uid=euclid,dc=example,dc=com
uniqueMember: uid=riemann,dc=example,dc=com
uniqueMember: uid=euler,dc=example,dc=com
uniqueMember: uid=gauss,dc=example,dc=com
uniqueMember: uid=test,dc=example,dc=com
ou: mathematicians
cn: Mathematicians
objectClass: groupOfUniqueNames
objectClass: top
We can see that the most specific objectClass that is available is groupOfUniqueNames, so we will specify that as our filter
filter: "(objectClass=groupOfUniqueNames)"
The next values to configure are userAttr and groupAttr. Notice in the mathamaticians object that there are multiple users listed via the uniqueMember attribute:
uniqueMember: uid=euclid,dc=example,dc=com
uniqueMember: uid=riemann,dc=example,dc=com
uniqueMember: uid=euler,dc=example,dc=com
uniqueMember: uid=gauss,dc=example,dc=com
uniqueMember: uid=test,dc=example,dc=com
We need to match the values of the uniqueMember attribute to an attribute of the users (in our case the Bernhard Riemann user) so that when the user tries to log in, Dex will correctly find that he is a member of the right group and allow access. The value in the user object that matches the uniqueMember attribute for Bernhard Riemann is the DN (Distinguished Name), so we will use that.
Together, our two values will look like this:
userAttr: DN groupAttr: uniqueMember
The last value to add is the groups name, and the attribute of the mathematicians object that correlates to that is the ou (Organizational Unit)
nameAttr: ou
All together our groupSearch looks like:
groupSearch:
baseDN: dc=example,dc=com
filter: "(objectClass=groupOfUniqueNames)"
userAttr: DN
groupAttr: uniqueMember
nameAttr: ou
The next step is to create some roleBindings for our users and groups in a file called bindings.yaml. The --- separator indicates that these are two different objects in the same yaml file.
In this example, we will create one role binding just for the riemann user and one that will grant access to any of the users in the mathematicians group. In our example, both are assigned to the same role.
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: riemann-admin roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: riemann --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: clusterAdminGroup roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: oidc:mathematicians
5. Applying and Testing Configuration
Putting it all together, our LDAP configuration should look like this:
apiVersion: v1
kind: Secret
metadata:
name: ldap-password
namespace: kommander
type: Opaque
stringData:
password: password
---
apiVersion: dex.mesosphere.io/v1alpha1
kind: Connector
metadata:
name: ldap
namespace: kommander
spec:
enabled: true
type: ldap
displayName: LDAP connector test
ldap:
host: ldap.forumsys.com:389
insecureNoSSL: true
bindDN: cn=read-only-admin,dc=example,dc=com
bindSecretRef:
name: ldap-password
userSearch:
baseDN: dc=example,dc=com
filter: "(objectClass=inetOrgPerson)"
username: uid
idAttr: uid
emailAttr: mail
groupSearch:
baseDN: dc=example,dc=com
filter: "(objectClass=groupOfUniqueNames)"
userAttr: DN
groupAttr: uniqueMember
nameAttr: ou
If we apply these, we'll see the following messages:
kubectl apply -f ldap.yaml secret/ldap-password created connector.dex.mesosphere.io/ldap created
kubectl apply -f bindings.yaml clusterrolebinding.rbac.authorization.k8s.io/riemann-admin created clusterrolebinding.rbac.authorization.k8s.io/clusterAdminGroup created
We can see that the objects have been created and we can modify them or check them by referring to the names listed above. Next, lets check if the user riemann in the group clusterAdministrator is properly authenticated:
$ kubectl auth can-i get pods --namespace kube-system --as riemann --as-group oidc:mathematicians --as-group system:authenticated
yes
This will either return yes or no depending on if your authentication was successful. The next step is to attempt generating a user token and attempt logging into the DKP dashboard. You can navigate to the cluster and attempt to generate a token via the url: https://CLUSTER_URL/token. If it was successful, you should see the following output:
{
"iss": "https://cluster_url/dex",
"sub": "CgdyaWVtYW5uEhNkZXgtY29udHJvbGxlci1sZGFw",
"aud": "dex-controller-dex-dka-client-kube-apiserver",
"exp": 1710952253,
"iat": 1710865853,
"at_hash": "PI6pg5m4ylzk4N4RuBLP9A",
"c_hash": "oj4_TXso2VSbjsIy2LurLQ",
"email": "riemann@ldap.forumsys.com",
"email_verified": true,
"groups": [
"mathematicians"
]
}
If you do not see any groups populated, then your groupSearch is misconfigured and you will need to identify any typos or errors before continuing. Your login may appear successful even though the group is not added, so ensure that everything appears correct. The last test is to attempt to log into the ops-portal via:
dkp open dashboard
Username: ...
Password: ...
URL: https://CLUSTER_ADDRESS/dkp/kommander/dashboard
If your user is not in an authorized group, or your rolebinding for that user or group does not have the proper permissions, you will only see:
Not Authorized
To troubleshoot issues logging in with LDAP credentials, check the dex-kubeaddons pod:
kubectl logs -n kommander -l app=dex ttime="2024-03-19T16:30:52Z" level=info msg="performing ldap search dc=example,dc=com sub (&(objectClass=inetOrgPerson)(uid=riemann))"
time="2024-03-19T16:30:52Z" level=info msg="username \"riemann\" mapped to entry uid=riemann,dc=example,dc=com"
time="2024-03-19T16:30:52Z" level=info msg="performing ldap search dc=example,dc=com sub (&(objectClass=groupOfUniqueNames)(uniqueMember=uid=riemann,dc=example,dc=com))"
time="2024-03-19T16:30:52Z" level=info msg="login successful: connector \"dex-controller-ldap\", username=\"\", preferred_username=\"\", email=\"riemann@ldap.forumsys.com\", groups=[\"mathematicians\"]"
This guide should help to facilitate your LDAP configuration with DKP. If you still have issues, please open a ticket with our support team for further guidance. Be sure to include a dkp diagnose bundle as well as details about the users/groups you are attempting to log in with.