Зачем Kubernetes нужна двухфакторная аутентификация и как подойти к её внедрению
Двухфакторная аутентификация (2FA) для Kubernetes - это не overengineering, а базовый элемент защиты production-среды от компрометации. Встроенные механизмы аутентификации k8s полагаются на статические токены, сертификаты или файлы конфигурации, которые при утечке дают злоумышленнику полный контроль. Внедрение 2FA решает эту проблему, добавляя второй независимый фактор проверки личности.
Архитектура решения строится на разделении доступа для людей и машин. Человеческий доступ к kubectl и веб-интерфейсам проходит через OIDC-провайдер с поддержкой 2FA. Автоматизированные системы, такие как CI/CD-пайплайны, используют сервис-аккаунты с ограниченными правами, которые не требуют второго фактора. Для реализации вам потребуются ингресс-контроллер (например, Nginx Ingress) и OIDC-провайдер, например Keycloak или Dex.
Эта стратегия закрывает ключевые риски без усложнения автоматизированных рабочих процессов. Внедрение требует настройки нескольких компонентов, но результат - уровень безопасности, соответствующий современным требованиям compliance.
Сценарии атак, от которых защищает 2FA
Рассмотрим конкретные ситуации, показывающие необходимость второго фактора:
- Утечка файла ~/.kube/config. Если файл конфигурации с токеном или сертификатом попадёт к злоумышленнику, он получит прямой доступ к API-серверу Kubernetes с правами владельца. С 2FA этот токен сам по себе бесполезен - потребуется код из приложения-аутентификатора.
- Атака на Kubernetes Dashboard, выставленный в интернет. Частая ошибка - развернуть Dashboard и открыть к нему доступ через Ingress или LoadBalancer без дополнительной аутентификации. Это создаёт публичную точку входа. Настройка OIDC через ингресс-контроллер гарантирует, что перед доступом к интерфейсу пользователь пройдёт проверку в Keycloak или другом провайдере с включённым 2FA.
- Компрометация рабочей станции администратора. Если на компьютере инженера запущено вредоносное ПО, оно может перехватить активную сессию kubectl или файлы аутентификации. Даже в этом случае для новой аутентификации потребуется второй фактор, что ограничивает ущерб.
Защита production-среды - основная цель. В development или staging-окружениях требования могут быть мягче, но для кластера, где работают бизнес-критичные приложения, 2FA переходит из категории рекомендации в обязательное требование.
Обзор архитектуры решения: OIDC, ингресс и сервис-аккаунты
Общая схема выглядит так:
- Аутентификация пользователя. Инженер выполняет
kubectl get pods. Плагин kubectl-oidc перенаправляет его в браузер на страницу OIDC-провайдера (Keycloak). Пользователь вводит логин, пароль и код 2FA из приложения. После успешной проверки провайдер возвращает kubectl ID-токен, который используется для запросов к API Kubernetes. - Защита веб-интерфейсов. Запрос к Kubernetes Dashboard поступает на ингресс-контроллер. Контроллер, настроенный с аннотациями для OAuth, выступает как прокси аутентификации. Он перенаправляет пользователя на ту же страницу Keycloak с 2FA. После успешного входа ингресс добавляет в запрос к Dashboard заголовки с именем пользователя и передаёт его дальше.
- Доступ для автоматизации. Сервис-аккаунт в namespace
ci-cdимеет свой токен и привязанную Role с ограниченными правами (например, только на создание pod-ов в определённых namespace). GitLab Runner или Jenkins используют этот статический токен в kubeconfig. Так как это доверенная система, 2FA не требуется. Принцип наименьших привилегий минимизирует риски от компрометации этого токена.
Эта архитектура гибкая. OIDC-провайдер можно интегрировать с корпоративным LDAP/AD, а ингресс-контроллер заменить на специализированный прокси, например, oauth2-proxy.
Настройка OIDC-провайдера и подключение Kubernetes API
Практическая реализация начинается с развёртывания OIDC-провайдера и его подключения к API-серверу Kubernetes. Мы используем Keycloak как популярное и функциональное решение.
Установка и базовая конфигурация Keycloak как OIDC-провайдера
Установите Keycloak в ваш кластер с помощью Helm-чарта. Это предпочтительный метод для интеграции с k8s.
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install keycloak bitnami/keycloak \
--namespace keycloak --create-namespace \
--set auth.adminUser=admin \
--set auth.adminPassword=YourStrongAdminPassword123 \
--set service.type=ClusterIP
После установки получите внешний адрес сервиса. Для production используйте Ingress с TLS.
Войдите в административную консоль Keycloak. Создайте новый realm (например, «kubernetes»). В этом realm создайте клиента OIDC:
- Client ID:
kubernetes - Client Protocol:
openid-connect - Access Type:
confidential - Valid Redirect URIs:
http://localhost:8000/*(для kubectl-oidc) иhttps://your-ingress-auth-url/*(для ингресса)
На вкладке «Credentials» сохраните сгенерированный Client Secret. Он понадобится для настройки. Затем включите и настройте фактор TOTP (Time-based One-Time Password) в разделе «Authentication» → «Flows». Назначьте его обязательным для браузерного потока входа.
Создайте пользователей и группы. Для интеграции важно правильно настроить маппинг утверждений (claims) в токене. Убедитесь, что claim preferred_username заполняется. Это будет использоваться для идентификации пользователя в Kubernetes.
Для углубленного понимания разницы между аутентификацией и авторизацией и работы протоколов, изучите наше практическое руководство по аутентификации и авторизации. Там подробно разобраны OAuth 2.0, JWT и модели контроля доступа.
Конфигурация API-сервера Kubernetes для работы с OIDC
Теперь нужно сообщить kube-apiserver о новом провайдере аутентификации. Для этого добавляются флаги командной строки.
Если кластер развёрнут с помощью kubeadm, отредактируйте статический Pod-манифест API-сервера:
kubectl edit pod kube-apiserver-your-control-plane-node -n kube-system
В секцию spec.containers[0].command добавьте следующие аргументы:
- --oidc-issuer-url=https://keycloak.your-domain.com/auth/realms/kubernetes
- --oidc-client-id=kubernetes
- --oidc-username-claim=preferred_username
- --oidc-groups-claim=groups
- --oidc-ca-file=/etc/kubernetes/pki/oidc-ca.crt # Если используется собственный CA
Если вы используете публичный TLS-сертификат от Let's Encrypt или подобного центра, флаг --oidc-ca-file может не потребоваться. После сохранения изменений Pod kube-apiserver автоматически перезапустится. Проверьте логи, чтобы убедиться в отсутствии ошибок:
kubectl logs kube-apiserver-your-control-plane-node -n kube-system | grep -i oidc
В логах должна появиться строка о успешной загрузке OIDC-провайдера. На этом этапе API-сервер готов принимать ID-токены, выданные вашим Keycloak.
Создание и использование kubeconfig с OIDC-аутентификацией
Классический kubeconfig с токеном или сертификатом заменяется на конфигурацию с exec-плагином. Плагин отвечает за интерактивный процесс аутентификации через браузер.
Установите клиентский плагин kubectl-oidc или используйте встроенные возможности kubectl (начиная с версий ~1.23). Пример конфигурационного файла ~/.kube/config:
apiVersion: v1
kind: Config
users:
- name: devops-engineer
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: kubectl-oidc
args:
- "--issuer-url=https://keycloak.your-domain.com/auth/realms/kubernetes"
- "--client-id=kubernetes"
- "--client-secret=your-client-secret-from-keycloak"
- "--extra-scopes=offline_access"
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUd... # Ваш CA сертификат кластера
server: https://api.your-k8s-cluster:6443
name: production-cluster
contexts:
- context:
cluster: production-cluster
user: devops-engineer
name: prod
current-context: prod
При первом выполнении команды, например, kubectl get nodes, плагин откроет браузер и перенаправит на страницу входа в Keycloak. После ввода логина, пароля и кода TOTP из приложения (Google Authenticator, Authy) плагин получит токен и выполнит команду. Токен обновляется автоматически.
Теперь доступ к кластеру защищён двухфакторной аутентификацией. Убедитесь, что ваша локальная среда соответствует стандартам безопасности. Основы системного администрирования Linux, включая настройку безопасности, рассмотрены в нашем практическом руководстве по Linux.
Защита веб-интерфейсов: Kubernetes Dashboard и K9s через ингресс
Графические интерфейсы - вторая критическая точка входа. Их защита строится на использовании ингресс-контроллера как прокси с принудительной аутентификацией.
Настройка Ingress-контроллера с OIDC-аутентификацией
Мы используем Nginx Ingress Controller с модулем ngx_http_auth_request_module. Убедитесь, что он установлен. Создайте секрет с данными OIDC-клиента:
kubectl create secret generic keycloak-oauth --namespace=ingress-nginx \
--from-literal=client-id=kubernetes \
--from-literal=client-secret=your-client-secret-from-keycloak
Разверните Kubernetes Dashboard, если он ещё не установлен. Затем создайте Ingress-ресурс для Dashboard со специальными аннотациями:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubernetes-dashboard
namespace: kubernetes-dashboard
annotations:
nginx.ingress.kubernetes.io/auth-url: "https://keycloak.your-domain.com/auth/realms/kubernetes/protocol/openid-connect/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://keycloak.your-domain.com/auth/realms/kubernetes/protocol/openid-connect/auth?client_id=kubernetes&response_type=code&scope=openid&redirect_uri=$scheme://$host$request_uri"
nginx.ingress.kubernetes.io/auth-response-headers: "X-Auth-Request-Preferred-Username, Authorization"
nginx.ingress.kubernetes.io/auth-snippet: |
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
nginx.ingress.kubernetes.io/configuration-snippet: |
auth_request_set $username $upstream_http_x_auth_request_preferred_username;
proxy_set_header X-Forwarded-User $username;
spec:
ingressClassName: nginx
tls:
- hosts:
- k8s-dashboard.your-domain.com
secretName: dashboard-tls-secret
rules:
- host: k8s-dashboard.your-domain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kubernetes-dashboard
port:
number: 443
Важно: в настройках клиента kubernetes в Keycloak Redirect URI должен включать адрес вашего ингресса: https://k8s-dashboard.your-domain.com/*.
Теперь при попытке зайти на https://k8s-dashboard.your-domain.com Nginx перенаправит вас на страницу входа в Keycloak с запросом кода 2FA. Только после успешной аутентификации запрос будет пропущен к Dashboard.
Интеграция аутентификации с сервисной учётной записью Dashboard
Dashboard по умолчанию работает под сервис-аккаунтом kubernetes-dashboard в своём namespace. Однако нам нужно, чтобы права пользователя внутри кластера определялись не этим аккаунтом, а его личной идентификацией из OIDC-токена.
Для этого необходимо передать имя пользователя из заголовка, который добавляет ингресс (X-Forwarded-User), в Dashboard. Современные версии Dashboard поддерживают режим пропуска токена (--token-ttl=0), когда аутентификация делегируется внешнему прокси.
Главный шаг - создать в Kubernetes ClusterRoleBinding, который свяжет пользователя или группу из OIDC с ролью внутри k8s. Например, чтобы дать всем пользователям из группы k8s-admins в Keycloak права cluster-admin:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: oidc-cluster-admins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: k8s-admins
Теперь пользователь, прошедший 2FA и входящий в группу k8s-admins в Keycloak, получит соответствующие права в Dashboard и через kubectl. Безопасность передачи заголовков критична: используйте TLS на всех соединениях между ингрессом, Keycloak и Dashboard, чтобы предотвратить подмену идентификатора.
Для K9s или других инструментов, которые также могут быть доступны через веб, применяется аналогичный подход с настройкой ингресса. Правильная настройка SSL/TLS termination - важная часть этой конфигурации. Разные архитектурные подходы к этой задаче подробно разобраны в статье «SSL/TLS termination в Kubernetes: сравнение архитектур».
Организация доступа для автоматизации: сервис-аккаунты без 2FA
Автоматизированные системы не могут интерактивно вводить код из приложения-аутентификатора. Для них используются сервис-аккаунты Kubernetes - специальные учётные записи для не-человеческих сущностей. Их ключевая особенность в контексте 2FA - они аутентифицируются статическим токеном или сертификатом, что позволяет беспрепятственно работать CI/CD-пайплайнам, операторам и другим автоматическим процессам.
Создание безопасного сервис-аккаунта для CI/CD
Принцип наименьших привилегий здесь важен как никогда. Не используйте сервис-аккаунт default или широкие права cluster-admin. Создайте изолированное пространство и аккаунт с конкретными разрешениями.
apiVersion: v1
kind: Namespace
metadata:
name: ci-cd
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: gitlab-runner
namespace: ci-cd
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deploy-role
namespace: ci-cd
rules:
- apiGroups: ["apps", ""]
resources: ["deployments", "services", "configmaps", "secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: gitlab-runner-binding
namespace: ci-cd
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: deploy-role
subjects:
- kind: ServiceAccount
name: gitlab-runner
namespace: ci-cd
Теперь получите токен для этого сервис-аккаунта. Kubernetes автоматически создаёт для него секрет.
kubectl get secret -n ci-cd -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='gitlab-runner')].data.token}" | base64 --decode
Этот токен - конфиденциальные данные. Храните его в специализированных системах. Для управления подобными секретами в production рекомендуем ознакомиться с нашим полным руководством по работе с Kubernetes Secrets.
Интеграция с популярными CI-системами: GitLab CI и GitHub Actions
Используйте полученный токен для настройки доступа из систем непрерывной интеграции.
Для GitLab CI/CD. Создайте переменную среды в проекте или группе GitLab, например, KUBE_CONFIG. Её значением будет целый kubeconfig файл, использующий токен сервис-аккаунта.
apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data:
server: https://api.your-k8s-cluster:6443
name: prod
contexts:
- context:
cluster: prod
namespace: ci-cd
user: gitlab-runner
name: prod
current-context: prod
users:
- name: gitlab-runner
user:
token:
Закодируйте этот YAML в base64 и поместите в переменную. В .gitlab-ci.yml эта переменная будет автоматически раскодироваться и использоваться.
Для GitHub Actions. Используйте официальный экшен azure/setup-kubectl и передайте ему kubeconfig через секрет репозитория.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: azure/setup-kubectl@v3
with:
kubectl-version: 'v1.28'
- name: Configure kubeconfig
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBE_CONFIG }}" | base64 --decode > $HOME/.kube/config
- name: Deploy
run: kubectl apply -f deployment.yaml
Критическое правило: никогда не коммитить файлы kubeconfig или токены напрямую в git-репозиторий, даже приватный. Используйте встроенные механизмы секретов вашей CI-системы.
Для комплексной проверки безопасности не только аутентификации, но и других аспектов инфраструктуры, используйте наш готовый план аудита безопасности IT-инфраструктуры с чек-листами и командами для Docker, Kubernetes и Nginx.
Резюме и рекомендации по поддержке безопасного кластера
Внедрение двухфакторной аутентификации в Kubernetes - многоэтапный процесс, но он фундаментально повышает безопасность кластера. Ключевой принцип: человеческий доступ через OIDC с 2FA, машинный доступ через ограниченные сервис-аккаунты.
Чек-лист для пошагового внедрения:
- Развернуть OIDC-провайдер (Keycloak) в кластере или рядом с ним.
- Настроить в провайдере клиента для Kubernetes, включить обязательный TOTP.
- Добавить флаги OIDC в конфигурацию kube-apiserver и перезапустить его.
- Сгенерировать новые kubeconfig-файлы для пользователей с использованием exec-плагина (kubectl-oidc).
- Настроить Ingress для веб-интерфейсов (Dashboard) с аннотациями аутентификации к OIDC-провайдеру.
- Создать RBAC-правила (ClusterRoleBinding), связывающие группы/пользователей из OIDC с ролями в Kubernetes.
- Для автоматизации создать отдельные namespace, сервис-аккаунты и выдать им минимально необходимые права через Role и RoleBinding.
- Интегрировать токены сервис-аккаунтов в CI/CD-системы через защищённые переменные.
После внедрения настройте мониторинг и аудит. Включите и настройте Kubernetes Audit Logging для отслеживания всех запросов к API-серверу. Логи должны отвечать на вопросы: кто (user.username), что (resource, verb), когда и откуда. Это необходимо для расследования инцидентов.
Установите регулярную процедуру ротации секретов: клиентского секрета OIDC в Keycloak и токенов сервис-аккаунтов, используемых в автоматизации. Рассмотрите использование внешних систем управления секретами, таких как HashiCorp Vault, для динамического генерации кратковременных учётных данных.
Двухфакторная аутентификация - мощный, но не единственный элемент защиты. Дополнительно изучите и внедрите Network Policies для сегментации трафика между pod-ами, примените Pod Security Standards (или Admission Controllers, например, Kyverno, OPA Gatekeeper) для обеспечения безопасности workload-ов. Комплексный подход, начинающийся с контроля доступа, - залог устойчивости вашего production-кластера.