We are bringing the best of Tectonic to Red Hat OpenShift to build the most secure, hybrid Kubernetes application platform.
Tectonic Identity is an authentication service for both Tectonic Console and kubectl
. It facilitates communication to the API server on the end user's behalf. All Tectonic clusters enable Role Based Access Control (RBAC). Tectonic Identity can be mapped to an LDAP service ensuring RBAC role bindings for groups and users map to your exiting LDAP system.
This document describes managing users and access control in Tectonic and Kubernetes using LDAP.
Tectonic Identity is configured through the Tectonic Console to allow for LDAP user authentication. In order to integrate with an LDAP server, you'll need the following:
Follow these steps in Tectonic Console to enable LDAP authentication in your cluster:
Add an LDAP service account capable of querying for groups and users.
objectClass
of person.The example configuration above translates to the following diagram:
objectClass
of groupOfNames.member: cn=john,dc=example,dc=org
in the LDAP directory, are using the Distinguished Name (DN) attribute.The example configuration above translates to the following diagram:
The following is a sample LDAP directory used in the test steps.
# john, example.org
dn: cn=john,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
uid: john.doe
mail: john.doe@example.org
cn: john
sn: doe
userPassword:: e1NTSEF9dkltSFZkNTgzN3JBaVdEZ2xyVXFyeE9nM1FETHBkM04=
# jane, example.org
dn: cn=jane,dc=example,dc=org
objectClass: person
objectClass: inetOrgPerson
uid: jane.doe
mail: jane.doe@example.org
cn: jane
sn: doe
userPassword:: e1NTSEF9dkltSFZkNTgzN3JBaVdEZ2xyVXFyeE9nM1FETHBkM04=
# tstgrp, groups, example.org
dn: cn=tstgrp,ou=groups,dc=example,dc=org
objectClass: top
objectClass: groupOfNames
member: cn=john,dc=example,dc=org
cn: tstgrp
In this example the user john.doe
's dn
is in tstgrp
, but jane.doe
is in no groups. You can query for these users in the Test Configuration page to verify this.
Keep a backup of the existing config in case something goes wrong during the update.
To apply a new Tectonic Identity configuration to your Kubernetes cluster:
kubectl apply
: $ kubectl apply -f ~/Downloads/new-tectonic-config.yaml
If successful the following message is displayed:
configmap "tectonic-identity" configured
$ kubectl patch deployment tectonic-identity \
--patch "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"date\":\"`date +'%s'`\"}}}}}" \
--namespace tectonic-system
If successful the following message is displayed:
"tectonic-identity" patched
In order for an LDAP user to have any access to Kubernetes resources, both from the console and kubectl, you must setup role bindings. See Configuring Access for more details.
To use kubectl
as an LDAP user:
kubectl
configuration.kubectl
configuration file. For example: export KUBECONFIG=~/Download/kubectl-config
Until otherwise modified, you can still use your static account for further administrative setup.
Access configuration requires understanding Kubernetes Roles, RoleBindings, ClusterRoles, and ClusterRoleBindings. LDAP-based users do not alter this model. LDAP usernames and groups can be used with Kubernetes bindings; visit the following to learn how to set up these configurations:
The following shows an example of granting user john.doe@example.org
basic access to the cluster.
support-readonly
that can run commands get, logs, list, and watch for namespaces and pods: apiVersion: rbac.authorization.k8s.io/v1alpha1
kind: ClusterRole
metadata:
name: support-readonly
rules:
- apiGroups:
- ""
attributeRestrictions: null
resources:
- namespaces
- namespaces/finalize
- namespaces/status
- pods
verbs:
- get
- logs
- list
- watch
john.doe
's group tstgrp
: kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1alpha1
metadata:
name: support-reader
namespace: kube-system
subjects:
- kind: Group
name: tstgrp
roleRef:
kind: ClusterRole
name: support-readonly
apiGroup: rbac.authorization.k8s.io
Tectonic Console and kubectl
now reflect the updated role and binding:
$ kubectl --kubeconfig=johnDoeConfig --namespace=tectonic-system get pods
NAME READY STATUS RESTARTS AGE
default-http-backend-4080621718-f3gql 1/1 Running 0 2h
kube-version-operator-2694564828-crpz4 1/1 Running 0 2h
...
An attempt to access a resource or perform a command to which a user does not have access will be rejected by the API server:
$ kubectl --kubeconfig=johnDoeConfig --namespace=tectonic-system get services
Error from server (Forbidden): the server does not allow access to the requested resource (get services)
Regardless of the identity provider being used, authorization is performed by using the email address of the user attempting to be authorized. For example, if john.doe@example.org is marked as an admin, admin access is given only if the user logs in by providing the same email address. If the user attempts to log in with anything other than email, role binding policies are not applied. This issue is observed due to a Kubernetes limitation when Dex is used as the OpenID Connect provider.
If a subject other than the email attribute is used to log in, Kubernetes will prefix the field with the issuer URL and considers the new string as the username. For example, logging in with the uid, john.doe, makes it intuitive that it's the subject in the role binding that is matched on. Kubernetes adds extra strings to john.doe and provide https://john.doe-example.org/identity#(UID)
. As a result role binding fails because there is no match between the username and the value of the subject name
in ClusterRoleBinding.
To work around, use the email attribute when mapping users to roles. The following outlines an example LDAP configuration for the user john.doe and an associated ClusterRoleBinding.
john.doe, Users, 5866a86d3187bc712e435b35, example.org
dn: uid=john.doe,ou=Users,o=5866a86d3187bc712e435b35,dc=example,dc=org
givenName: john
jcLdapAdmin: TRUE
uid: john.doe
uidNumber: 5006
loginShell: /bin/bash
homeDirectory: /home/John.doe
sn: Doe
cn: John Doe
objectClass: exampleUser
gidNumber: 5006
mail: john.doe@example.org
memberOf: cn=tectonic_users,ou=Users,o=5866a86d3187bc712e435b35,dc=example,dc=org
In the following example, email address is provided as the name attribute to work around the Kubernetes limitation.
apiVersion: rbac.authorization.k8s.io/v1alpha1
kind: RoleBinding
metadata:
name: admin-john.doe-namespace-all-access-binding
namespace: john.doe-namespace
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: john.doe@example.org
subjects:
- kind: User
name: john.doe
namespace: john.doe-namespace
To troubleshoot users and groups configuration, check the tectonic-console
's logs to see what LDAP query is being sent.
Locate the Console's pod name:
$ kubectl --namespace=tectonic-system get pods
NAME READY STATUS RESTARTS AGE
tectonic-console-3824021701-50j0x 1/1 Running 0 2h
tectonic-identity-3193269714-bg19p 1/1 Running 0 24m
tectonic-ingress-controller-99581103-rd0cj 1/1 Running 0 2h
Using kubectl
, tail the logs for the console pod:
$ kubectl --namespace=tectonic-system logs -f tectonic-console-3824021701-50j0x
2017/01/29 22:29:47 ldap: no results returned for filter: "(&(objectClass=person)(mail=jane2.doe@example.org))"
2017/01/29 22:30:16 ldap: groups search with filter "(&(objectClass=groupOfNames)(member=john.doe@example.org))" returned no groups
In the above example, two issues are visible. First, jane2.doe@example.org
was not found in the LDAP directory. Second, a group search is attempting to check if the member field contains john.doe@example.org
. However, the original example and LDAP server output, shown earlier in this document, qualify members based on DN
rather than mail
.