Create a Kubernetes User Sandbox in Docker Enterprise

When you create a user in Docker Enterprise Edition (EE), that user can immediately create a Swarm service on the cluster. All they need to do is generate, download, unzip and “execute” their client bundle. However, on the Kubernetes side Role Based Access Control (RBAC) and the default user permissions are quite a bit different. I will show you how to get a similar experience with Kubernetes that you get with the out-of-the-box experience of Swarm.

Docker EE creates a client bundle which contains certificates, environment variables, etc. necessary to setup your system to talk to the cluster using the docker and kubectl commands. On a Windows 10 system, you use the command below in a PowerShell window. On a Linux system, you would use source env.sh at a Bash shell prompt.

ken> Import-Module .\env.ps1
Cluster "ucp_ken-ucp.lab.capstonec.net:6443_ken.rider" set.
User "ucp_ken-ucp.lab.capstonec.net:6443_ken.rider" set.
Context "ucp_ken-ucp.lab.capstonec.net:6443_ken.rider" modified.

This sets up their local environment to talk to the remote Docker EE cluster. When they then execute the docker service create command, it creates the service on the cluster using the Swarm orchestrator.

ken> docker service create --name nginx nginx:1.14-alpine
zaslrujj7y0rrp53b1ds9q7as
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged

With Docker EE 2.0 and, now, 2.1, Kubernetes is also supported as an orchestrator for the cluster. However, if this same user tries to create a similar service using Kubernetes, it fails.

ken> kubectl create deployment nginx --image=nginx:1.14-alpine
Error from server (Forbidden): deployments.extensions is forbidden: User "8f796584-5683-4c24-baf8-554ad21ad86f" cannot create deployments.extensions in the namespace "default": access denied

In the Swarm case, when Docker EE creates a user it sets up a collection, /Shared/Private/ken.rider, and two grants. The first grant, ken.rider > Restricted Control > /Shared/Private/ken.rider, gives the user restricted control over the his or her private collection. The second grant, ken.rider > Scheduler > /Shared, gives the user the ability to schedule work on the worker nodes in the cluster. When the user creates a service, it is deployed in that collection.

In the Kubernetes case, Docker EE supports Kubernetes RBAC but it doesn’t setup any namespaces, roles or role bindings for the user. In simple terms, namespaces allow us to segregate objects in a Kubernetes cluster; roles define what a user or group can do to/with objects; and role bindings attach users and groups with roles over a namespace. (For a more complete discussion of Kubernetes RBAC, see Using RBAC Authorization in the Kubernetes reference documentation.)

To (somewhat) replicate what Docker EE does for Swarm users for Kubernetes users, we will need to define the corresponding namespace, role and role binding for them. The following Kubernetes manifest will apply these for the user ken.rider.

kind: Namespace
apiVersion: v1
metadata:
  name: user-kenrider
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: user-kenrider-full-access
  namespace: user-kenrider
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["batch"]
  resources:
  - jobs
  - cronjobs
  verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    subjectName: ken.rider
  name: ken.rider:user-kenrider-full-access
  namespace: user-kenrider
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: user-kenrider-full-access
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: ken.rider

If you create a file with the above, for example user-ken.rider.yml, and apply it using an administrator’s client bundle, you will see the following.

admin> kubectl apply -f .\user-ken.rider.yml
namespace "user-kenrider" created
role.rbac.authorization.k8s.io "user-kenrider-full-access" created
rolebinding.rbac.authorization.k8s.io "ken.rider:user-kenrider-full-access" created

Note: you will notice that the username is ken.rider but the namespace is user-kenrider (without the period). Kubernetes is very restrictive about the characters allowed in namespace names. The regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?'. You will see there are several characters missing in this expression that might be problematic for you. In particular, a lot of organizations use a period, ‘.’, or underscore, ‘_’, in usernames. They may also use uppercase letters in their usernames. Finally, if you’re using the integrated LDAP, Active Directory, or OAuth authentication, it’s very likely the user principal name (UPN) will be used as the Docker EE username and, in most cases, that will be the user’s email address which contains an at sign, ‘@’.

Now when the user uses their client bundle and specifies the namespace we created, they can deploy their service.

ken> kubectl --namespace user-kenrider create deployment nginx --image=nginx:1.14-alpine
deployment.extensions "nginx" created

User Namespace

In this blog post, we have created a Kubernetes sandbox for a user. You can use the above example to create your own manifest template and script to create a per-user sandbox for each user you create in a Docker EE cluster.

Leave a Reply