Kubernetes Authentication and Authorization through Dex & LDAP and RBAC rules

Emin Aktaş
Trendyol Tech
Published in
9 min readOct 20, 2021

--

Written by developer-guy Emin Aktaş

Let's start by giving a little bit of introduction about Authentication, Authorization, and the difference between the two.

Authentication is the act of validating that users are who they claim to be. Thus, in the most basic form, we can say that the authentication process is verifying the identity of the users.

As we said, with the authentication process now, we have the identity of the users, which means that we know the users who are operating on the system. So here comes the question, what is the significance of this identity? And what can we do with this identity? In response to this, we can say: "Many things", but today we'll be answering as "Authorization".

Authorization in system security is the process of giving the user permission to access a specific resource or function. This term is often used interchangeably with access control or client privilege.

To better understand the relationship between the two, it might help to think of the two terms in this way: Authentication asks "Who are you?" and authorization asks "What are you allowed to do?"

Credit: https://www.okta.com/identity-101/authentication-vs-authorization/

You might be asking that why it is so important. Let's answer this by thinking from the Kubernetes perspective. You have to make your clusters secure in various ways because security is a very high concern task in today's world. You can't ignore the security risks, so you have to protect your clusters against attacks. The first thing that you can apply easily and quickly on your cluster is monitoring the actions in your cluster. A concept called Audit Logs in Kubernetes might give you an insight into what is happening in your cluster in near real-time. To be meaningful, we have to provide an identity to our users to see who is operating on our clusters. The next step is restricting the actions based on these identities because we know who you are right now by defining fine-grained rules, and here is the authorization.

Today, we'll focus on implementing Authentication via Dex and dex-k8s-authenticator projects based on LDAP (Lightweight Directory Access Protocol) and Authorization via RBAC (Role-Based Access Control) natively supported by Kubernetes.

Table of Contents

Introduction

Kubernetes authentication means validating the identity of who or what is sending a request to the Kubernetes API Server. For example, a request can originate from a pod, within a cluster, or from a human user. Therefore, Kubernetes authentication is needed to secure an application by validating the identity of a user.

After validating the user's identity, the next is applying RBAC rules for authorization which checks if the validated user has access to the operation in the Kubernetes cluster. In other words, this is the way to limit actions that users can do on the cluster based on the user's groups or specifically for the user.

RBAC uses the rbac.authorization.k8s.io API group to drive authorization decisions, allowing you to dynamically configure policies through the Kubernetes API using Role/RoleBinding, and ClusterRole/ClusterRoleBinding resources.

Kubernetes does not offer any native implementation for creating and managing users, which means it does not have any object-stores for users or groups. This fact allows admins to integrate their organization's identity service provider.

We have a couple of options as authentication plug-ins such as X.509 Client Certs, Static Token File, OpenID Connect Tokens, Webhook Token, and Authenticating Proxy in Kubernetes.

In this guide, we will use the OpenID Connect Tokens authentication plug-in.

OpenID is a secure way to log in. You only share your information with the OpenID provider, and it tells the website about who you are. For example, we are always using this method in logging in to many other websites, like logging in to a website with your Google account.

Credit: http://openidexplained.com/

Dex is an open-source CNCF sandbox project and an identity service that uses OpenID Connect to drive Authentication for other apps.

Dex comes with many different connectors for Authentication, such as GitHub and LDAP. You can see all the supported connectors from here. But LDAP is a crucial tool here for big organizations, and this is why we will be focusing on LDAP connectors and deploying OpenLDAP for installing LDAP locally in this guide.

Dex's LDAP connector allows us to log in with a username/password-based authentication. Then, Dex handles the protocols for our sake, issues a signed JWT token, and serves us as a portal to other identity providers through connectors.

Lightweight Directory Access Protocol shortly LDAP which makes it possible for an application to query user information. This is the place where usernames, passwords, email addresses, groups are stored.

Then, suppose we want to automatically generate kubeconfig files based on the credentials that we retrieved from the identity provider. In that case, this is where dex-k8s-authenticator gets involved because this project can help us display kubectl commands on the browser to generate a kubeconfig file, which we can use to authenticate to the cluster later on.

What are we trying to solve?

Credit: https://twitter.com/vicnastea/status/1449617473490210820?s=20

Today, we will assume that we have a problem with managing credentials within kubeconfig files. That matters because we are trying to achieve shift-left security, which refers to moving security sooner in the development process, so we'll be sharing kubeconfig files with our development teams to deploy their applications on top of Kubernetes clusters. In the light of this informations, as you might guess, we have to identify users and restrict their operations based on fine-grained rules to reach safer days.

Let's talk about Day 0. We have a ServiceAccount token with broader scoped permissions which we used as a user within the kubeconfig file that we shared with our development teams. Unfortunately, this leads us to several problems:

  • First, we can't detect the actual user of the action via Audit Logs.
  • Second, users can do nearly everything they want because of the broader scoped permissions to the ServiceAccount.
  • Third, we have to create and distribute kubeconfig files manually.
  • There is no time limit on the token used by the user.
  • Finally, there is no easy way to do fine-grained control over the RBAC rules. (LDAP group + ClusterRole mapping)

So, by setting up the proper Authentication and Authorization methods, we'll be addressing all of the problems above.

Let's try all of these on locally with Minikube cluster

Now, it is time to do practice to get the real taste of it. We will be using a repository called che-auth-playground which contains all steps as scripts. We will explain what is hidden in the scripts in the article.

Prerequisites:

  • minikube v1.23.2
  • kubectl v1.21.4
  • helm v3.7.0

Let's start by cloning the repository for the demo.

$ git clone https://github.com/che-incubator/che-auth-playground.git
$ cd che-auth-playground/minikube_dex

The following script is in the minikube_dex folder, which will be used and detailed here.

  • 01_minikube_start.sh
  • 02_certs.sh
  • 03_dex.sh
  • 04_minikube_apiserver.sh
  • 13_dex-k8s-authenticator.sh
  • 14_openldap.sh
https://gist.github.com/eminaktas/3ec95074e54aa89ed8be7eb9733fcfd6

The first script creates the Kubernetes cluster. We suggest that minikube is not using Docker as a driver for this demo! It might cause problems with ingress and DNS. Because of that, we'll be using a magic DNS called nip.io in the demo. We certainly suggest you use VirtualBox driver.

https://minikube.sigs.k8s.io/docs/drivers/

https://gist.github.com/eminaktas/68d411ff36e77af9e3a1dc69a0801937

Dex can be accessible from both web browsers and the Kubernetes API server; we need to create a self-signed certificate or use an existing certificate signed by a trusted authority. Today, we will be making a self-signed certificate and storing it in a Kubernetes secret and copying the certificates with the minikube's built-in file sync mechanism in the minikube VM to use later on in the process. Please do not confuse the folder path(~/.minikube/files), and it is a particular folder for minikube.

https://gist.github.com/eminaktas/3ab6144513fbe63495319f41e3acaf48

Here is the script for deploying the Dex on top of Kubernetes with playing YAML manifest files. This also stores the OpenLDAP user DN and OpenLDAP password in Kubernetes secrets. You might notice that the script is storing Github information. On purpose, We remain it you might want to use the Github authentication method in one day. But quick reminder here we are focusing on LDAP in this guide.

If you haven't created GitHub OAuth before, click here to create one to access the GitHub API to authenticate through Dex.

https://gist.github.com/eminaktas/3fff419b4a33806a1a2d64b825512cc2

Next, we'll configure the Kubernetes API Server here with the OIDC variables we've created earlier. As you can see, we are providing some vital information to API Server. These are provided while we are deploying Dex in the manifest file. We are giving an id and a secret (random string) to the static client.

https://gist.github.com/eminaktas/5f1a89f2d36f481b42048b6dc9e62e2b

As we mentioned before, dex-k8s-authenticator is our static client here. Alternatively, you can write your own or use another tool as static clients such as gangway, loginapp, and kubelogin.

The script will configure the values.yaml according to the values we used earlier. Finally, the dex-k8s-authenticator will be deployed with Helm. You'll notice that we provide the ca.pem and trusted root ca in the values.yaml, which are our tickets to access the Kubernetes cluster.

https://gist.github.com/eminaktas/06fa715baf0dc778dfd32000009c3ea8

Lastly, we will deploy our OpenLDAP server. Then, In the LDIF file, as you can see, we define two users and one group called clusterusers defined here. We created this group to map RBAC rules based on the group, which is better than assigning the roles based on each username.

User informations -> user01/password01 and user02/password02

1
2

So far, so good, everything should be working fine. After logging into the dex-k8s-authenticator with the LDAP authentication method, you will be welcomed by this page to configure access to the Kubernetes cluster with the user.

dex-k8s-authenticator

You can create your own RBAC rules based on clusterusers group, and you should see an output like the below screenshot. Don't panic in the first output. We haven't defined the RBAC rule in the first place. After determining the roles, you'll see that API Server will respond to your requests successfully.

Let's give cluster-admin Role for the clusterusers group.

https://gist.github.com/eminaktas/079be4271e02b3cd65e86f349f4483b3
$ kubectl apply -f https://gist.githubusercontent.com/eminaktas/079be4271e02b3cd65e86f349f4483b3/raw/01d4ede3d32d82c0cb489919c6236292852680ab/admin-cluster-role-binding.yaml

And, user01 and user02 have cluster-admin Role privileges from now on.

The process works as follows:

Workflow

Furthermore

In this guide, we talked about the LDAP integration of Dex, but, as we mentioned above, there are various connectors types supported by Dex. Therefore, you can consider another one that might be more suitable for your organizational needs. For example, you might want to authenticate your users through GitHub credentials. You can continue to use Dex for it. There is a very detailed blog post for this, and please see.

Also, in this guide, we stood on deploying Dex on top of Kubernetes, but this is not the only solution for deploying Dex. We can deploy Dex as a standalone or HA manners without running it on Kubernetes. Unfortunately, there is a lack of documentation on this subject, but I found some valuable discussions and issues:

Conclusion

Security is now the heart of everything nowadays. By simply adding a layer before your developers reach out to your cluster, you can reduce the potential risk in your cluster and one of the practices for securing insensitive workloads. To summarize all of this, Dex and dex-k8s-authenticator are perfect solutions that work together seamlessly if we want to enable Authentication on top of Kubernetes clusters. Authorization complements Authentication, so don't forget to enable RBAC rules against the identities you retrieved through the Authentication phase. Dex also supports various types of connectors, and you can choose one that meets your needs if you don't want to use LDAP as an upstream identity provider.

References

--

--