How do you issue a Kubernetes client certificate through the CertificateSigningRequest API, and how does the API server derive the username and groups?
answer
- subject fields become identity
- signer name for API clients
- approve, then read status
- one-year cap unless shorter requested
- masters group is refused
basics
~20 sSubmit their PKCS#10 request as a CertificateSigningRequest with signer kubernetes.io/kube-apiserver-client, approve it with kubectl certificate approve, and read status.certificate. The API server takes the certificate's CN as the username and each O as a group.
solid answer
~40 sThe engineer creates a key and a request with subject `CN=<username>` and `O=<group>`. You wrap it in a `certificates.k8s.io/v1` `CertificateSigningRequest` with `signerName: kubernetes.io/kube-apiserver-client`, `usages: ["client auth"]` and a short `expirationSeconds`, then run `kubectl certificate approve`. The csrsigning controller in kube-controller-manager signs it with the cluster CA, capped at `--cluster-signing-duration` (one year by default), and you copy `status.certificate` into a kubeconfig user entry. At request time the API server maps CN to the username and every O to a group, plus `system:authenticated`. The `CertificateSubjectRestriction` admission plugin blocks `O=system:masters` for this signer, and you still need an RBAC binding for the user or group.
code
yaml · 10 linesapiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: maya-okafor
spec:
request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K...
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 32400
usages:
- client authgo deeper
Remember the chain: request, CSR object, approve, read status.certificate, add to kubeconfig, then bind RBAC.
Explain CN-to-username and O-to-groups mapping, the kube-apiserver-client signer, the client auth usage, and how expirationSeconds interacts with the signing-duration cap.
Treat approval as a security control: inspect the decoded subject, keep lifetimes short, split create and approve rights, and note that CSR objects are garbage-collected an hour after approval.
Judge where certificate issuance belongs at all: fine for break-glass and small clusters, but frozen groups and no revocation make it a poor team-wide login.
## No User object, so identity lives in the credential Kubernetes stores **no User object**. When a person authenticates with an X.509 **client certificate**, the API server trusts any certificate that chains to its client CA (the `--client-ca-file`) and reads the identity straight out of the certificate subject: - **CN** (Common Name) becomes the **username**, for example `CN=maya.okafor`. - Each **O** (Organization) value becomes a **group**, for example `O=fraud-rules-dev`. - Every authenticated request also gets the group `system:authenticated`. A certificate with no CN is rejected. Whatever you put in the subject at signing time is fixed until the certificate expires, which matters later for revocation. ## The CertificateSigningRequest flow The **CertificateSigningRequest** (CSR) API, `certificates.k8s.io/v1`, lets you have the cluster CA sign a certificate without anyone copying the CA key around. The steps for onboarding one engineer on the fraud-rules engine team: 1. The engineer generates a private key and a PKCS#10 request whose subject is `CN=maya.okafor/O=fraud-rules-dev`. The private key never leaves their machine. 2. An admin wraps the base64-encoded request in a cluster-scoped `CertificateSigningRequest` object with `signerName: kubernetes.io/kube-apiserver-client`, `usages: ["client auth"]` and, ideally, `expirationSeconds`. 3. An admin runs `kubectl certificate approve <name>` (or `deny`). This updates the `approval` subresource. 4. The **csrsigning** controller in kube-controller-manager sees the approved request and signs it with the cluster signing CA (`--cluster-signing-cert-file` and `--cluster-signing-key-file`), writing the result to `status.certificate`. 5. The admin or engineer reads `status.certificate`, decodes it, and builds a kubeconfig user entry with the certificate and the private key. 6. An RBAC binding grants the username or group what it needs; without one, the engineer authenticates but is forbidden from almost everything. ```bash kubectl apply -f maya-csr.yaml kubectl get csr kubectl certificate approve maya-okafor kubectl get csr maya-okafor -o jsonpath='{.status.certificate}' | base64 -d > maya.crt kubectl config set-credentials maya --client-certificate=maya.crt --client-key=maya.key --embed-certs=true ``` ## Guard rails built into the API | Rule | Where it is enforced | Effect | |---|---|---| | Approving needs the `approve` verb on the `signers` resource for that signer name | `CertificateApproval` admission plugin | Creating CSRs and approving them can be delegated separately | | `O=system:masters` is refused for `kubernetes.io/kube-apiserver-client` | `CertificateSubjectRestriction` admission plugin (on by default) | Nobody can mint a superuser certificate through this signer | | `usages` may contain only `client auth`, `digital signature` and `key encipherment`, and must include `client auth` | csrsigning controller | Server certificates cannot be obtained through this signer | | `expirationSeconds` below 600 is invalid | API validation | The shortest request is ten minutes | | Lifetime is capped at `--cluster-signing-duration` (default 8760h, one year) | csrsigning controller | A request for longer is silently shortened | | Approved and denied CSRs are deleted after one hour, pending ones after 24 hours | CSR cleaner controller | Fetch the certificate promptly | ## What approvers must actually check The approver is the only human check in the chain, so `kubectl certificate approve` should never be reflexive: - Decode the request (`openssl req -noout -subject` on the decoded `spec.request`) and confirm the CN matches the person and every O is a group they should hold. - Confirm the requester (`spec.username` on the CSR, filled in by the API server) is someone allowed to ask on that person's behalf. - Prefer a short `expirationSeconds` (for example 32400 seconds, a nine-hour shift) over the one-year default, because the API server never checks certificate revocation. ## Operating it day to day A few habits keep the certificate path safe once it is in use: - Keep a record of every approved subject and expiry date outside the cluster, because CSR objects disappear an hour after approval and are no inventory. - Give CSR creation to a small onboarding group and approval to a different one, so no single person can issue their own certificate. - Check the resulting identity with `kubectl auth whoami` using the new kubeconfig before handing it over. - Bind the username to a namespaced Role first, such as edit rights in `fraud-rules`, and widen only on request. ## Where this sits This path is well suited to a small cluster, a lab, or break-glass credentials. For a team-wide login it scales poorly: every joiner needs an approval, groups are frozen into the certificate, and a leaver's certificate cannot be revoked, which is why most platforms move humans to an OIDC identity provider and keep certificates for emergencies.
- Why can't someone use the CSR API to mint a certificate with O=system:masters?The `CertificateSubjectRestriction` admission plugin, enabled by default, rejects any CSR for `kubernetes.io/kube-apiserver-client` whose subject contains the `system:masters` organization. That group bypasses authorization entirely, so a certificate carrying it could never be reined in by RBAC. Approving is also gated separately: the approver needs the `approve` verb on the `signers` resource for that signer.
- The engineer requested expirationSeconds of 63072000 (two years). What lifetime do they get?At most the value of kube-controller-manager's `--cluster-signing-duration`, which defaults to 8760h, one year. The csrsigning controller honours a requested lifetime only when it is shorter than that cap, and API validation rejects anything under 600 seconds. Nothing fails; the certificate is simply shorter than requested, which is worth checking in its `notAfter`.
saying these in an interview costs you the question
- Kubernetes stores a User object that the certificate is linked to.
- The username comes from the kubeconfig user entry's name.
- Creating the CSR object is enough; the kube-controller-manager signs it automatically.
- Deleting the CSR object later invalidates the issued certificate.
- Groups for a certificate user are managed with kubectl on the cluster.