How do engineers manage RBAC in today’s world? More importantly, how much of a headache is it?
This is going to be the first piece of content in a series of content that’s going to showcase managing Kubernetes with Portainer vs managing Kubernetes standalone.
In this blog post, you’ll learn all about RBAC, why it’s important, and how you can manage it in Kubernetes and in Portainer.
Perhaps you’re asking yourself why you’d want to read this content, or better yet, why it’s needed in the first place. Let’s break it down.
Have you ever been in a house that was just put up by builders? As in, there’s really no inside and it’s not ready to be moved into. If you haven’t, when you walk into a house that builders just put up, it’s just wood with some insulation. The rooms are carved out, but there’s nothing in them. There’s a space for the bathroom, but there’s no plumbing.
There are a few locations for ceiling lights, but you’re unsure if they’re going to go there.
In short, it’s a “pick your own destiny” situation.
That’s literally what Kubernetes is.
Kubernetes is a frame of a house that builders just put up that day without anything on the inside. To be honest, that was the point of it. Kubernetes is supposed to be an orchestration tool that you customize to fit your needs. Need a little ingress? Pick an ingress controller. Need some networking? Pick a CNI. Need a Service Mesh? Here are a few to choose from.
In short - pick your own adventure.
Because of that, Kubernetes is a platform that needs you to choose what you’re going to do with it and how you’re going to manage it. The purpose of this content is to help you with that decision, and that’s where Portainer comes into play.
Now that that’s got that out of the way, let’s dive into the RBAC piece of choosing your adventure.
What is RBAC?
Since we’ve already started talking about houses in this blog post, let’s keep our house analogy.
Two things happen when you’re at someone’s home:
- You walk into the house.
- You’re told what you can and cannot do inside of the house.
When you walk into the house, that’s authentication. You’ve been given permission to walk into the house.
When you’re told what you can and cannot do in a house, that’s authorization. Someone is telling you “you can use this guest bathroom, but not the bathroom upstairs”.
RBAC works inside of Kubernetes (and plenty of other platforms) as an authorization tool. You’re able to define for other engineers and users what they can and cannot do inside of a Kubernetes cluster. Maybe they can just list Kubernetes resources, or maybe they can just create Pods but not Ingress Controllers. As you’re creating RBAC permissions, you get to choose the adventure of (and for) others.
The authentication piece usually comes a step before the RBAC piece and that could be done with a wide range of methods in the OpenID Connect (OIDC) space. Anything from Azure Active Directory to Okta. With that being said, User Management is going to be a separate piece of content.
Once a Service Account is created, it can then be given a Role or ClusterRole, but before that, the Role needs to be created.
The code below creates a new ClusterRole, which means that the Role can be used throughout the cluster. Standard Roles (without Cluster in front of them in the Kubernetes resource) means that they’re Namespace scoped. The ClusterRole is pointing to a specific Kubernetes resource (Pods) and it’s stating what the Role can do (the verbs). As you can see, this is essentially a “read-only” role for Pods.
Once the ClusterRole is created, it can be used, but how? There’s the Service Account and the ClusterRole, but how can the Service Account utilize the ClusterRole? That’s where ClusterRoleBindings or RoleBindings come into play.
The Binding attaches the ClusterRole to the Service Account (or a user/group, but in this example it’s a Service Account). As you can see below, the ClusterRoleBinding is stating that the mikeuser Service Account is going to have a ClusterRole attached to it. The ClusterRole that’s being attached is the reader ClusterRole, which was the name of the ClusterRole in the code above.
Pretty straightforward, right? Well, interestingly enough, it’s not. In fact, RBAC is the bane to an engineer's existence when it comes to Kubernetes. It seems straightforward when you’re managing one Service Account, but what about hundreds? Not to mention the users (engineers) and groups that also need authorization permissions for a Kubernetes cluster. Also, let’s not forget that chances are there isn’t just one Kubernetes cluster. That means you have to manage RBAC in this fashion in multiple locations for multiple people/service accounts.
Implementing RBAC Standalone
As a reminder, this blog post isn’t about user management in Kubernetes. However, to create a Role and RoleBinding and attach it to a user, a user needs to exist. Because of that, let’s briefly look at what it takes to create a user for Kubernetes without any thirdparty OIDC solution.
If you look at the above, it’s already not off to a good start. There’s a ton you have to do just to get a user created to be used inside Kubernetes. The code breakdown above is to:
- Create a user.
- Generate a cert for a user.
- Set the Kubernetes context for the user.
Next, you have to create either a ClusterRole or a Role for the user. Remember, the difference between a ClusterRole and a Role is that a Role is namespace-scoped and a ClusterRole can be used throughout the Kubernetes cluster in any namespace.
The ClusterRole below is called pod-creator and it gives anyone or any Service Account with this ClusterRole the ability to create and read Pods.
After the ClusterRole is created, you have to bind it to a user.
Once complete, you’ll have a ClusterRole, ClusterRoleBinding, and user.
Now, here’s the problem (well, multiple problems).
You have to do this for each Kubernetes cluster.
You have to perform these actions for each user (if they have different Roles).
That’s a lot of manual effort. Sure, you can set it up in a pipeline and automate it, but you still have to write every single ClusterRole, ClusterRoleBinding, Role, and RoleBinding. It’s extremely cumbersome and it’s also very easy to lose track of what Role/ClusterRole is doing and who has access.
Sidenote: Before it sounds like this blog post is trying to paint a negative picture for standalone Kubernetes, just a friendly reminder that it’s not. Remember, Kubernetes wasn’t created to make RBAC easy. It wasn’t created to manage all of your RBAC Kubernetes Manifests. It was created to be an orchestrator and the rest is up to you to choose your own adventure. This isn’t a “negative” when it comes to Kubernetes. This process feels hard in Kubernetes because it is. Because it wasn’t meant to be easy. Why? Because it’s not the purpose of what Kubernetes by itself is trying to accomplish.
Implementing RBAC in Portainer
Now that you’ve learned how to manage RBAC in standalone Kubernetes, let’s dive into what it looks like in Portainer.
First, go to Environments —> Manage access.
You’ll see a screen (like in the screenshot below) showcasing environment access. This is for the entire cluster, so think about this like ClusterRoles and ClusterRoleBindings.
What’s happening below is you’re given an option to select a user or a service account that you’ve created in Portainer (which you’ll see in another piece of content around user management). You can also select a group (a team) for the Role. For example, maybe it’s a team of developers that should only have read-only permissions.
After the user is chosen, choose what RBAC role you want to give the user. You can choose what type of ClusterRole you want to attach (bind, like a ClusterRoleBinding) to the user, service account, or group/team.
There are five pre-determined Roles that are the most common throughout many production-level environments that range from full administrator/root to read-only permissions.
Once you choose which Role/permission you’d like to go with, click the blue + Create access button.
And just like that, RBAC is configured for your Kubernetes cluster.
There’s no question about it - managing RBAC in Portainer is a far superior method than managing it with a bunch of YAML.
If you look at the above scenarios, plus the fact that with Kubernetes standalone you have to run the same RBAC configurations for each cluster manually, it’s a no-brainer who wins this street fight. Portainer all the way. Why? It’s honestly so much easier.
If you'd like to give Portainer a try, you can get 3 nodes free here.