kubectl inside Pod

By adding specific privileges, you can execute kubectl within a container to operate on clusters.
The standard Kubernetes way for managing container privileges is using Role resource.

For the assurance of RBAC and scalability, directly assigning a Role to a Pod is not possible. Instead, you need both RoleBinding and ServiceAccount, creating the following references:

Role <- RoleBinding -> ServiceAccount <- Pod

Additionally, some hosting platforms like GKE may provide authentication separate from the standard Kubernetes accounting.
As described later, authorization using Role allows granular permission assignments on an individual resource basis and is suitable for scenarios where the target of operations is clear. Authentication in GKE, for example, is well-suited for controlling a wide range of cluster resources or controlling GCP functions outside the cluster through API when the target is not explicitly within the Kubernetes API.

In very old Kubernetes clusters, the RBAC authorization feature itself may not be enabled. In such cases, version upgrades or configuration changes may be necessary.

kubectl for containers

kubectl command that you ultimately want to run should be added to the container image in advance.
It can operate with either package additions provided by the distribution or officially distributed binaries.

With Role setup, additional authentication plugins are not required since it utilizes the standard Kubernetes API.

Role

The resource spec for Role is thoroughly explained in the official guide.

As mentioned earlier, Role defines authorization permissions:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list"]

In a container granted the above permission set, kubectl get pods will work as intended.

Defining the permissions available in rules block can be challenging without an easy way to know the keywords to specify.

  • rules.[].apiGroups specifies the resource classification, using the URI obtained by removing the version from each resource’s apiVersion string.
    • Core APIs, including operations like Pod manipulation, can be specified using the shorthand notation "". While it is concise as a string, the concept is not immediately evident. For instance, since networking.k8s.io is not a core API, it won’t work without explicitly mentioning the URI, making it less intuitive.
  • rules.[].resources denotes the specific target of operations. In this example, sub-resources are not immediately obvious.
    • This item specifies the path in the HTTP API of Kubernetes, and one could identify it with an HTTP API reference.
  • rules.[].verbs represents operation categories in a manner similar to HTTP methods. Although it corresponds to kubectl subcommands, it is not entirely the same label, making it less obvious.
    • For example, the resource update operation corresponding to kubectl apply requires either update or patch permissions, but there is no straightforward means to determine.

Role or ClusterRole

The permissions specified by Role are limited to resources within the metadata.namespace.
To grant permissions for broader resources in one go, you would use ClusterRole and its corresponding ClusterBinding.

If you can pinpoint the target of operations, using the narrower-scoped Role is more secure.

ServiceAccount

ServiceAccount is an unattended user. Basically, it defines labels that represent its purpose.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-serviceaccount
  namespace: default

By specifying serviceAccountName in the podSpec of resources like Deployment, the Pod operates with the designated ServiceAccount.

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      serviceAccountName: my-serviceaccount
      containers:
      - name: nginx
        image: nginx:latest

RoleBinding

In this example, RoleBinding is a resource that associates ServiceAccount with Role, and it simply references them once their names are determined appropriately.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: ServiceAccount
  name: my-serviceaccount
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-and-pod-logs-reader
  apiGroup: rbac.authorization.k8s.io

In this example, it may seem like there is simply an added overhead because there is only one ServiceAccount. However, the design is intended to minimize unexpected security vulnerabilities by allowing changes to the subjects list at any time and keeping the roleRef fixed.

中馬崇尋
Chuma Takahiro