Implementing 2FA Kubernetes Access via Gateway API, Dex and MULTIDIRECTORY

A Russian cybersecurity company replaced static kubeconfig files with corporate accounts and mandatory 2FA for its Talos Linux Kubernetes clusters. The solution routes all authentication through a single FQDN using NGINX Gateway Fabric, Dex as an OIDC provider connected to MULTIDIRECTORY via LDAP, and kube-oidc-proxy for token validation and impersonation. Groups stored in the directory are passed directly into RBAC bindings, eliminating manual certificate management. A lightweight Python service dynamically generates kubeconfig files that contain no secrets. The team documented several Gateway API migration pitfalls including namespace route restrictions and BackendTLSPolicy hostname validation. The approach keeps the entire configuration in Git and avoids modifying kube-apiserver flags.

HabrTranslated from Russian

Read at source

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.

Meridian digestThe week's most consequential security stories, distilled into one briefing.See the digest

More in Other

Mail.ru Reduces Lifetime 1TB Cloud Storage Promo to Standard 8GB Quota for Select Users
Kimi K3 Open Model Surpasses Closed AI Leaders with Million-Token Context and 896 Experts
Innostage Completes Functional Testing of PT NGFW 1.10.3 Across 156 Criteria