How-To Guide
Manage helix-prod Admin Access¶
Goal: Issue, renew, onboard, and offboard personal cluster-admin access to helix-production.
Time: ~10 minutes to issue a certificate; ~2 minutes to renew one.
Why needed: helix-production has no identity provider and no jumphost.
The Kubernetes API (https://api.helixpass.net:6443) is reachable from anywhere, so a personal, short-lived client certificate is the access control.
Before You Start¶
Each admin has a personal client certificate, not a shared kubeconfig.
Authorization comes from a single
ClusterRoleBindingnamedhelix-admins.Its user subjects are listed in
helix-infra-charts/admin-access/config.yaml— that file is the authoritative admin list, deployed via ArgoCD.Certificates are valid for 90 days (
kubernetes.io/kube-apiserver-clientsigner). Kubernetes cannot revoke a client certificate, so removing a name fromconfig.yaml— not certificate expiry — is what cuts off access.For the full rationale (why certificates, why user subjects instead of a group binding, why 90 days) and a detailed risk discussion, see
admin-access/README.mdin thehelix-infra-chartsrepository.
Prerequisites¶
kubectlandopensslinstalled locally.To issue a certificate (approver role):
realpath, and an active kubectl context pointing at helix-prod. Verify withkubectl cluster-info— it must showhttps://api.helixpass.net:6443.A checkout of
helix-infra-charts/admin-access/scripts/admin-cert.sh.
Run every command below from that script’s directory:
cd helix-infra-charts/admin-access/scripts
Your key, CSR, certificate, and ca.crt are written to ~/.kube/helix-admin/ (directory mode 0700, key mode 0600); the kubeconfig context is merged into your default kubeconfig (~/.kube/config, mode 0600).
Override the location with the ADMIN_CERT_DIR environment variable.
Never copy the private key elsewhere, and never commit it to a repository.
Issue a New Certificate¶
The three steps below apply both to a brand-new admin and to a renewal that has already expired (see “Renew Your Certificate” below for the one-command self-renewal path).
Step 1: Request a Key and CSR (You)¶
./admin-cert.sh request phil
Expected output:
Dateien in /home/phil/.kube/helix-admin: phil.key (bleibt hier), phil.csr
OK: /home/phil/.kube/helix-admin/phil.csr an einen helix-Admin senden. Der Key bleibt auf DIESEM Rechner.
This creates phil.key and phil.csr (CN=phil, O=helix-admins) in ~/.kube/helix-admin/.
Send the .csr file to an existing helix-prod admin over any channel — its content is not secret.
The .key file never leaves your machine.
Step 2: Issue the Certificate (Approver)¶
The approver runs this with an active kubectl context on helix-prod:
./admin-cert.sh issue phil ~/Downloads/phil.csr
Expected output:
certificatesigningrequest.certificates.k8s.io/helix-admin-phil created
certificatesigningrequest.certificates.k8s.io/helix-admin-phil approved
subject=O=helix-admins, CN=phil
notAfter=Oct 13 2026 GMT
OK: /home/jens/.kube/helix-admin/phil.crt + /home/jens/.kube/helix-admin/ca.crt an phil zurücksenden (nicht geheim).
Before signing, issue verifies the CSR subject: CN must equal the name you passed and O must be exactly helix-admins, otherwise it aborts unsigned.
This blocks a substituted CSR from being signed under a mismatched name or a privileged organization such as O=system:masters.
On success it creates a CertificateSigningRequest with expirationSeconds: 7776000 (90 days), approves it, downloads the signed certificate to phil.crt, and copies the cluster CA to ca.crt.
It deletes the CSR object again once the certificate is retrieved.
Send phil.crt and ca.crt back to the requester — neither is secret.
Step 3: Build the Kubeconfig (You)¶
./admin-cert.sh kubeconfig phil
Expected output:
OK: Kontext 'helix-prod' in /home/phil/.kube/config gemergt — sofort nutzbar mit: ktx helix-prod
This expects phil.crt, phil.key, and ca.crt to already sit in ~/.kube/helix-admin/, and merges a helix-prod cluster, user, and context into your default kubeconfig (~/.kube/config, or the first entry of $KUBECONFIG), embedding the certificate, key, and CA.
Existing contexts for other clusters are left untouched, and ktx sees helix-prod immediately — no manual merge step.
Verify Access¶
ktx helix-prod
kubectl auth whoami
Expected output:
ATTRIBUTE VALUE
Username phil
Groups [helix-admins system:authenticated]
kubectl auth can-i '*' '*'
Expected output:
yes
If can-i returns no, your name is not yet (or no longer) a subject in config.yaml — see “Onboard a New Admin” below.
Renew Your Certificate¶
Renewal is one command, run entirely by you, no second person needed — as long as your current certificate is still valid.
No RBAC change is needed either: the ClusterRoleBinding is untouched, only the certificate is replaced.
Switch to your helix-prod context first, then renew:
ktx helix-prod
./admin-cert.sh renew phil
This runs the same request and issue steps shown above (new key, new CSR, self-approved via your still-valid old certificate), then finishes with:
OK: User 'phil' im aktiven Kubeconfig in-place aktualisiert (Kontexte unverändert).
Your credentials are updated in place inside the active kubeconfig. The context and its ktx entry are untouched — no re-import needed.
kubectl auth whoami
Confirms phil / helix-admins, now backed by a fresh 90-day certificate.
Tip
renew only updates credentials in place when <name> matches the active context’s user, not just any matching entry in the file — this is what keeps a same-named user of a different cluster in a merged kubeconfig safe from being overwritten (which is why you run ktx helix-prod first).
If the active context is something else, renew instead merges a fresh helix-prod context into your default kubeconfig.
If you merge kubeconfigs from multiple clusters, give your helix-prod identity a name that is not reused as an active-context user elsewhere, so the in-place path always applies where you expect it.
Check Expiration¶
openssl x509 -in ~/.kube/helix-admin/phil.crt -noout -enddate
Expected output:
notAfter=Oct 13 2026 GMT
If the certificate has already expired, self-renewal is not possible — an expired certificate cannot authenticate the renewal request itself. Fall back to the three-step issuing process above, with another admin approving your CSR.
Onboard a New Admin¶
Add the name to
admins:inhelix-infra-charts/admin-access/config.yaml.Run
npm run buildinhelix-infra-charts/admin-access/.Commit and push to
main— ArgoCD syncs the updatedClusterRoleBindingautomatically.Have the new admin run
request, send you the CSR, and have an existing admin runissuefor them, as described in “Issue a New Certificate” above.
Offboard an Admin¶
Remove the name from
admins:inhelix-infra-charts/admin-access/config.yaml.Run
npm run build, commit, and push tomain.ArgoCD syncs within about a minute — authorization is revoked immediately, even though the certificate itself is still technically valid.
Warning
Kubernetes cannot revoke a client certificate.
A leaked or offboarded certificate keeps authenticating until it expires (up to 90 days) — removing the name from the ClusterRoleBinding subject list is what revokes authorization, and that takes effect immediately.
On a suspected key leak, remove the subject right away and report the incident; do not wait for certificate expiry.
Limits¶
No certificate revocation in Kubernetes — see the warning above; the
ClusterRoleBindingsubject list is the only immediate lever.Every admin can approve CSRs for any CN, inherent to holding
cluster-admin— the trust model assumes all admins are equally trusted.No API audit logging yet, and the API server is reachable from the public internet — both are tracked as follow-ups, not blockers.
Break-glass access, the tofu-generated admin kubeconfig, is unaffected by this workflow and held by Jens for emergencies.
For the full rationale and risk discussion, see admin-access/README.md in helix-infra-charts.