A Russian cybersecurity firm has published a detailed account of replacing static, long-lived kubeconfig certificates with corporate accounts and mandatory two-factor authentication across its Talos Linux Kubernetes clusters.
The previous approach relied on exchanging root kubeconfig files through a password vault. Each certificate was valid for a year, worked from any location, and could not be revoked without rotating the cluster CA. When an employee left or a laptop was lost, the credentials remained active.
Target requirements
The team defined four goals: login with corporate credentials, enforced second factor, cluster rights derived from directory groups, and a kubeconfig file containing no secrets.
Architecture components
- Talos Linux 1.13 as the immutable operating system
- Kubernetes v1.33
- ArgoCD for GitOps management
- NGINX Gateway Fabric 2.6 implementing Gateway API
- Dex 0.24 as the OIDC provider
- kube-oidc-proxy performing token validation and impersonation
- MULTIDIRECTORY as the LDAP source of truth for users, groups and 2FA policies
MULTIDIRECTORY supplies both LDAP attributes and 2FA enforcement. Dex connects to it with a standard LDAP connector; the second factor itself is configured only inside the directory, so neither Dex nor Kubernetes is aware of its existence.
Groups returned by Dex are placed in the OIDC token claim and forwarded by kube-oidc-proxy. Standard ClusterRoleBinding objects then grant permissions to those groups, allowing access changes to be performed solely by editing directory membership.
Single-host routing with Gateway API
All traffic arrives at one FQDN. An HTTPRoute splits requests among three backends: Dex OIDC endpoints, a Python kubeconfig generator, and kube-oidc-proxy. The catch-all rule for “/” does not override more specific prefixes, a behavior that differs from classic NGINX location ordering.
The generated kubeconfig uses the kubelogin exec plugin. It contains only the public cluster address, CA data and client ID; no certificates or tokens are embedded.
Gateway API migration issues
The team encountered several non-obvious problems. Routes placed in a different namespace from the Gateway were silently rejected because the listener defaulted to “Same” namespace. Explicitly setting allowedRoutes.namespaces.from: All resolved the issue. BackendTLSPolicy required the exact hostname present in the backend certificate rather than the internal service name, otherwise 502 errors occurred. Finally, the OIDC issuer URL had to remain identical inside and outside the cluster, solved with hostAliases on the proxy deployment.
All cluster-specific values were externalized into Kustomize patches and ArgoCD Application values, making the configuration reusable across additional clusters without code changes.


