Kubernetes Create User: Complete Guide to X.509 Certificates and RBAC

Share on Social Media

Still can’t perorm a Kubernetes Create user? Most engineers waste hours on CSR mistakes. Learn the exact X.509 + RBAC workflow CKA-certified pros use — before your cluster locks you out. #CentLinux #Kubernetes #RBAC



Introduction

Kubernetes does not maintain a user database. Instead, it relies on external identity sources — OIDC, cloud IAM, or X.509 client certificates — to authenticate human users. This guide walks through the exact workflow I use to create a user, issue a certificate through the Kubernetes certificate API, build a kubeconfig, and bind least-privilege RBAC permissions.


Why Kubernetes Requires Manual User Creation

Kubernetes draws a hard line between ServiceAccounts and users. ServiceAccounts are API objects managed by the cluster. Users are not. There is no kubectl create user command because Kubernetes deliberately delegates human identity to external systems.

Client certificate authentication works on a simple contract: the API Server trusts a Certificate Authority. Any certificate signed by that CA is accepted, as long as the CN (Common Name) and O (Organization) fields are formatted correctly. The CN becomes the username. The O becomes the group.

This means you can generate a key and CSR with openssl, submit the CSR to the Kubernetes certificate API, and receive a signed certificate — all without touching the cluster CA private key directly. That is significantly safer than manually signing certificates with the CA.

According to the 2025 Stack Overflow Developer Survey, Kubernetes appears in roughly 14% of U.S. technology job postings, and DevOps tooling accounts for about 30% of all tool mentions. User management and RBAC are among the most practical day-to-day skills for anyone operating a cluster.

Kubernetes Create User: Complete Guide to X.509 Certificates and RBAC
Kubernetes Create User: Complete Guide to X.509 Certificates and RBAC

Prerequisites

  • A working Kubernetes cluster with kubectl configured for admin access
  • openssl and base64 installed locally
  • Your current kubeconfig points to the target cluster

Step 1: Generate a Private Key and CSR

openssl genrsa -out ahmer.key 3072

genrsa generates an RSA private key. I recommend 3072 bits — stronger than 2048, with far less overhead than 4096. Treat this .key file as a secret. Anyone who obtains it can impersonate the user, because client certificate private keys cannot be password-protected in a way Kubernetes will accept.

openssl req -new -key ahmer.key -out ahmer.csr -subj "/CN=ahmer"

req -new creates a certificate signing request. The -subj flag defines the subject: /CN=ahmer sets the username to ahmer. If you want to assign the user to a group, use /CN=ahmer/O=developers. Group membership lets you bind RBAC to the group instead of individual users — a much better practice at scale.


Step 2: Base64-Encode the CSR

cat ahmer.csr | base64 | tr -d "\n"

The Kubernetes CSR object requires spec.request to be a single-line base64-encoded PEM string. tr -d "\n" strips newlines so the output is one continuous line. Skip this and kubectl apply will fail with a format error.


Step 3: Create the CertificateSigningRequest Resource

Create ahmer.yaml:

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: ahmer
spec:
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K...  # paste base64 output here
  signerName: kubernetes.io/kube-apiserver-client
  expirationSeconds: 86400
  usages:
  - client auth

Key fields:

signerName: kubernetes.io/kube-apiserver-client tells Kubernetes this CSR is for client authentication. The signer name determines what kind of certificate gets issued. Using the wrong signer results in rejection.

expirationSeconds: 86400 sets the certificate lifetime to one day. I strongly recommend short-lived certificates in production. The official Kubernetes hardening guidance is explicit: client certificates cannot be revoked individually. If a key leaks, the attacker can use it until expiry. Short lifetimes are the most effective mitigation.

usages: - client auth restricts the certificate to client authentication only. Do not add server auth or other usages.

kubectl apply -f ahmer.yaml --server-side

--server-side uses Server-Side Apply, avoiding the last-applied-configuration annotation bloat. For one-shot resources like CSRs, it keeps things clean.


Step 4: Approve the CSR and Retrieve the Certificate

kubectl get csr

You should see ahmer in Pending state. CSRs require explicit approval. This is a deliberate security control: being able to create a CSR does not mean you automatically get a certificate.

kubectl certificate approve ahmer

kubectl certificate approve sets the CSR to Approved. The Kubernetes certificate controller then signs the certificate and writes it to status.certificate.

kubectl get csr ahmer -o jsonpath='{.status.certificate}' | base64 -d > ahmer.crt

jsonpath extracts the base64-encoded certificate, and base64 -d decodes it into PEM format, saved as ahmer.crt.


Step 5: Configure kubeconfig

kubectl config set-credentials ahmer --client-key=ahmer.key --client-certificate=ahmer.crt --embed-certs=true

set-credentials creates a user entry named ahmer in kubeconfig. --embed-certs=true embeds the certificate and key contents directly into the kubeconfig file rather than referencing file paths. This is convenient for distribution but means the kubeconfig itself becomes a sensitive credential.

kubectl config set-context kubernetes-ahmer --cluster=kubernetes --user=ahmer

set-context creates a context that pairs the kubernetes cluster with the ahmer user. The context name is arbitrary but should be descriptive. Note that this does not switch to the context — it only defines it.


Step 6: Verify Authentication

kubectl --context kubernetes-ahmer auth whoami

auth whoami confirms which identity the API Server sees. In Kubernetes 1.27+, this returns the username, groups, and extra info. You should see ahmer as the username. If you set /O=developers, you will see developers in the groups list.

This step is critical. If authentication fails, the problem is almost always one of three things: the CSR was not approved, the certificate was not properly decoded, or the kubeconfig context references the wrong cluster or user.


Step 7: Create a Role and RoleBinding

kubectl create role developer --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods

kubectl create role creates a Role in the current namespace. This Role grants five verbs on pods: create, get, list, update, and delete. Notice what is not included: pods/exec, pods/log, pods/portforward, and any cluster-scoped resources. This is intentional least-privilege design.

kubectl create rolebinding developer-binding-ahmer --role=developer --user=ahmer

create rolebinding binds the developer Role to the ahmer user in the current namespace. The binding is namespaced. If you need cluster-wide access, use ClusterRole and ClusterRoleBinding — but be very deliberate about that decision.

At this point, ahmer can manage pods in the current namespace but nothing else. That is exactly the kind of scoped access you want for a developer who should not be able to read secrets, modify deployments, or touch other namespaces.


Step 8: Test the Permissions

kubectl get pods -A

Run this with the admin context first. Now try it with the restricted context:

kubectl --context kubernetes-ahmer get pods -A

You should see a Forbidden error. This is the correct result. The ahmer user can only list pods in the namespace where the RoleBinding exists. Attempting -A (all namespaces) requires cluster-scoped list permission, which was never granted.

Try these to confirm the boundary:

# Should succeed (if a pod exists in the current namespace)
kubectl --context kubernetes-ahmer get pods

# Should fail
kubectl --context kubernetes-ahmer get secrets

# Should fail
kubectl --context kubernetes-ahmer delete deployment nginx

Practical Advice from Production Experience

Always Use Short-Lived Certificates

One-day expiry is not inconvenient when you have automation. In my environments, I generate CSRs with 8-hour or 24-hour validity and rotate them automatically. The inability to revoke individual client certificates is a real operational risk that short lifetimes directly address.

Bind to Groups, Not Users

Individual user bindings do not scale. Create groups in the certificate subject (/O=developers, /O=platform-admins) and bind Roles to those groups. When someone leaves the team, you remove them from the group mapping — you do not hunt down every RoleBinding.

Never Grant cluster-admin to Human Users

I have seen this far too often. cluster-admin bypasses every RBAC check. If a developer needs to debug a production issue, give them a temporary Role with exactly the permissions required, bound to a short-lived certificate. Audit trails will thank you.

Use kubectl auth can-i for Validation

Before handing credentials to a user, verify the intended permissions:

kubectl --context kubernetes-ahmer auth can-i create pods
kubectl --context kubernetes-ahmer auth can-i delete secrets

The first should return yes, the second no. This is faster than asking the user to test and report back.

Prefer OIDC for Long-Term Production

Client certificates are excellent for lab environments, CI systems, and short-lived access. For a production cluster with dozens of engineers, OIDC with an identity provider (Okta, Azure AD, Google Workspace) is far superior. It gives you revocation, MFA, group sync, and audit integration that certificates cannot match.

Consider kubectl Plugin and Automation

Manually running these commands for every user is error-prone. Wrap the workflow in a script or a Helm chart. I have a small internal tool that takes a username and group list, generates the CSR, applies it, approves it, builds the kubeconfig, and outputs a ready-to-use file. It cut onboarding from 15 minutes to under 30 seconds.


Common Pitfalls

Forgetting tr -d "\n" on the base64 output. The CSR request field must be one line. This is the single most common mistake.

Using the wrong signerName. kubernetes.io/kube-apiserver-client is for client auth. Using kubernetes.io/kubelet-serving or another signer will fail or produce a certificate with the wrong purpose.

Not setting --embed-certs=true. Without it, the kubeconfig references file paths that may not exist on the user’s machine. Embedded certs make the kubeconfig portable.

Assuming the context switches automatically. kubectl config set-context defines a context but does not activate it. Use kubectl config use-context or --context explicitly.

Granting pods/exec by accident. If you use --resource=pods with * verbs, you do not get pods/exec. But if you add --resource=pods/exec, you are granting shell access to containers. That is a significant privilege escalation path. Grant it deliberately, never by default.


Video Tutorial

YouTube player

Summary

Creating a Kubernetes user is a multi-step process: generate a key and CSR, encode the CSR, submit it as a CertificateSigningRequest, approve it, retrieve the signed certificate, build a kubeconfig, and bind RBAC permissions. The workflow is manual by design — Kubernetes wants you to think carefully about identity and authorization.

The key takeaways:

  • Use 3072-bit RSA keys and short certificate lifetimes.
  • Bind RBAC to groups, not individual users.
  • Verify permissions with kubectl auth can-i before handing out credentials.
  • Prefer OIDC for production at scale.
  • Never grant more permissions than the user needs.

With these commands and practices, you can create a Kubernetes user that authenticates cleanly and operates within a tightly scoped set of permissions — which is exactly what a secure cluster requires.


Frequently Asked Questions

1. Can I revoke a Kubernetes client certificate after it has been issued?

No — not individually. This is the single most important limitation to understand about X.509 client certificate authentication in Kubernetes. Unlike ServiceAccount tokens, there is no revocation list, no kubectl revoke command, and no CRL (Certificate Revocation List) check in the API Server’s default authentication chain.

Once a client certificate is signed and the user presents it, the API Server accepts it until the certificate expires. Your only real mitigation options are:

  • Short certificate lifetimes — issue certificates valid for hours, not months
  • Rotate the cluster CA — invalidates every certificate signed by that CA, which is disruptive and rarely practical
  • Remove RBAC bindings — the user can still authenticate, but every API call returns Forbidden

The practical takeaway: treat short expiry as your revocation mechanism. If someone leaves the team, their certificate becomes useless within hours, not months. For anything longer-lived, use OIDC where you have real revocation through the identity provider.


2. Why does my user authenticate successfully but still get “Forbidden” on every command?

Authentication and authorization are two separate stages in Kubernetes, and this error means you passed the first but failed the second.

Authentication succeeded — your certificate is valid, signed by the trusted CA, and the API Server recognizes CN=ahmer as the username. If this stage failed, you would see Unauthorized (HTTP 401), not Forbidden (HTTP 403).

Authorization failed — there is no Role or ClusterRole bound to your user (or their group) that permits the requested verb on the requested resource in the requested namespace.

Debug it with:

kubectl auth can-i get pods --as=ahmer
kubectl auth can-i get pods --as=ahmer -n default
kubectl auth can-i '*' '*' --as=ahmer

Common causes:

  • RoleBinding is in the wrong namespace — RoleBindings only grant access within their own namespace
  • You used a Role but need cluster-scoped access — kubectl get nodes or kubectl get pods -A requires a ClusterRole and ClusterRoleBinding
  • Group mismatch — if you set /O=developers in the certificate but bound the Role to the user directly (or to a different group name), the binding will not match
  • Typo in the username — CN is case-sensitive and must match the RoleBinding subject exactly

3. What is the difference between kubernetes.io/kube-apiserver-client and other signerNames, and can I use a custom signer?

The signerName field tells the Kubernetes certificate controller what kind of certificate to issue and for what purpose. Choosing the wrong one either fails outright or produces a certificate the API Server will reject during authentication.

The built-in signers you will encounter:

Signer NamePurpose
kubernetes.io/kube-apiserver-clientHuman users and external clients authenticating to the API Server
kubernetes.io/kube-apiserver-client-kubeletKubelet client certificates
kubernetes.io/kubelet-servingKubelet serving certificates
kubernetes.io/legacy-unknownDeprecated; avoid
kubernetes.io/kube-apiserver-servingAPI Server serving certificates

For creating a user, you must use kubernetes.io/kube-apiserver-client. Using anything else will either be rejected or produce a certificate with the wrong extendedKeyUsage — and the API Server will refuse it at authentication time.

Custom signers are possible if you run your own signer controller (for example, cert-manager with a ClusterIssuer). But this is only worth doing if you need automated rotation, external CA integration, or certificate policy enforcement. For a handful of users, the built-in signer is sufficient and far simpler.


4. How should I handle certificate rotation for users without disrupting their access?

Rotation is where manual certificate workflows break down. Doing it by hand for every user every 24 hours is not sustainable, so you need automation. The pattern I use:

Overlap the certificates. Issue a new certificate before the old one expires, and keep both valid for a short window. The user’s kubeconfig can hold the new credentials while the old certificate is still accepted.

Automate the full pipeline. A rotation script should:

  1. Generate a new private key and CSR
  2. Create and apply the CSR object
  3. Approve it programmatically (using a controller with CSR-approver permissions)
  4. Fetch the signed certificate
  5. Update the user’s kubeconfig
  6. Notify the user or reload their client tooling

Use cert-manager if you can. It handles CSR creation, approval, renewal, and secret storage natively. A Certificate resource with a short duration and renewBefore gives you automatic rotation with no custom scripting.

Rotate more aggressively than you think you need to. Because you cannot revoke individual certificates, an 8-hour or 12-hour lifetime is far safer than a 24-hour one in a high-security environment. The overhead is in the automation, not the certificate itself — once the pipeline exists, shorter lifetimes cost nothing extra.


5. When should I use X.509 client certificates instead of OIDC for Kubernetes user authentication?

Both are valid, but they serve different operational realities. My rule of thumb after five years of running clusters:

Use X.509 client certificates when:

  • The cluster is small (a handful of users or automated systems)
  • Access is short-lived and granted for a specific task
  • You are working in a lab, CI pipeline, or break-glass scenario
  • You cannot integrate an external identity provider (air-gapped or heavily restricted environments)

Use OIDC when:

  • You have more than a few human users
  • You need MFA, SSO, or centralized identity lifecycle management
  • Audit requirements demand real revocation and detailed authentication logs
  • You want group membership managed in your IdP, not baked into certificate subjects
  • Users need to authenticate from multiple devices without sharing kubeconfig files

The honest answer for most production clusters in 2026 is OIDC for humans, X.509 for machines and short-lived break-glass access. X.509 certificates are excellent at what they do — they are just not designed for long-lived human identity at scale. Fighting that limitation with clever automation is more work than adopting OIDC in the first place.

If you are studying for the CKA exam, understand X.509 deeply — it is the foundation of Kubernetes authentication and appears frequently. But in the real world, treat it as one tool among several, not the default for every user.


If you’re eager to kickstart your journey into cloud-native technologies, “Kubernetes for the Absolute Beginners – Hands-on” by Mumshad Mannambeth is the perfect course for you. Designed for complete beginners, this course breaks down complex concepts into easy-to-follow, hands-on lessons that will get you comfortable deploying, managing, and scaling applications on Kubernetes.

Whether you’re a developer, sysadmin, or IT enthusiast, this course provides the practical skills needed to confidently work with Kubernetes in real-world scenarios. By enrolling through the links in this post, you also support this website at no extra cost to you.

Disclaimer: Some of the links in this post are affiliate links. This means I may earn a small commission if you make a purchase through these links, at no additional cost to you.


References

Kubernetes Documentation: https://kubernetes.io/docs/tasks/tls/certificate-issue-client-csr/



About the Author

Ahmer M
Ahmer M

Ahmer M

Sr. DevOps Engineer | CKA | RHCE | Freelancer | Blogger
I am a technology enthusiast with over 15 years of experience designing and scaling Linux, DevOps, and cloud environments. My expertise lies in container orchestration and automation, bridging the gap between development and operations to build resilient systems.


Leave a Reply