Post

Creating a Kubeconfig with Limited Permissions

Create a Limited kubeconfig for internal use

Creating a Kubeconfig with Limited Permissions

Creating a full-access Kubeconfig for your Kubernetes cluster is simple — but not always the most secure approach. In many cases, especially when working with automation, CI/CD pipelines, or giving access to external services, it’s better to generate a more restricted Kubeconfig tailored to specific needs.

In this post, I’ll show you how to create a Kubeconfig with limited permissions, ideal for scenarios where you want to allow just enough access to restart workloads like Pods, Deployments, or StatefulSets — without exposing your entire cluster.

Limit the Kubeconfig as much as you can. A CI pipeline that can only get/patch two resource types in one namespace is a pipeline that can’t do much damage if its secret ever leaks.


Prerequisites

Before getting started, make sure you have:

  • Access to a Kubernetes cluster with admin privileges.
  • kubectl installed and configured.
  • A namespace (or namespaces) where the limited user will operate.

Step 1: Create the ServiceAccount

Create a ServiceAccount that will be used to generate the Kubeconfig.

1
2
3
4
5
apiVersion: v1
kind: ServiceAccount
metadata:
  name: restart-bot
  namespace: home-assistant

Step 2: Create the ClusterRole

Create the role. Here we’re only allowing it to restart Deployments and StatefulSets.

1
2
3
4
5
6
7
8
9
10
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: restart-any-workload
rules:
  - apiGroups: ["apps"]
    resources:
      - deployments
      - statefulsets
    verbs: ["get", "patch"]

Step 3: Create the RoleBinding

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: restart-binding
  namespace: home-assistant
subjects:
  - kind: ServiceAccount
    name: restart-bot
    namespace: home-assistant
roleRef:
  kind: ClusterRole
  name: restart-any-workload
  apiGroup: rbac.authorization.k8s.io

Step 4: Create the token for the ServiceAccount

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Secret
metadata:
  name: restart-bot-token
  namespace: home-assistant
  annotations:
    kubernetes.io/service-account.name: restart-bot
type: kubernetes.io/service-account-token

Step 5: Build your Kubeconfig

  • certificate-authority-data: take the value from your original Kubeconfig.
  • token: take the value from the restart-bot-token secret created above.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Config
clusters:
- name: your-cluster
  cluster:
    server: https://cluster-ip:6443
    certificate-authority-data: <your original certificate>
users:
- name: restart-bot-ha
  user:
    token: <your token>
contexts:
- name: restart-bot-ha-context
  context:
    cluster: your-cluster
    user: restart-bot-ha
    namespace: home-assistant
current-context: restart-bot-ha-context

Never commit the generated Kubeconfig to git, even in a private repo. Store the token as a proper CI secret (GitHub Actions secret, Azure DevOps variable group, etc.) and template the rest of the file at deploy time.


✅ Done

You now have a Kubeconfig scoped to exactly one thing: restarting Deployments and StatefulSets in a single namespace. Reuse this pattern (ServiceAccount → ClusterRole → RoleBinding → token) whenever a CI pipeline needs cluster access — swap the verbs and resources for whatever that specific job actually needs, nothing more.

I use exactly this restricted Kubeconfig in the Bastion-SSH deployment for Home Assistant.

This post is licensed under CC BY 4.0 by the author.