Но когда после выполнения aws eks update-kubeconfig для настройки kubectl на своём маке наш бекенд-девелопер попытался подключиться:
root@ip-10-0-42-255:~# kubectl get nodes
error: You must be logged in to the server (Unauthorized)
Казалось бы — оба IAM пользователя с админ правами в AWS Console — что могло пойти не так?
Потому — начинаем искать причину, которая снова заставляет немного углубиться в процесс аутентификации и авторизации.
В топике ниже рассмотрим:
аутентификация vs авторизация
модули и процесс аутентификации пользователя в EKS — aws-iam-authenticator, AWS AIM
А в следующей части — авторизацию и RBAC в Kubernetes.
Содержание
Authentication vs Authorization
Для начала — поговорим о разнице между понятиями аутентификация и авторизация пользователя.
Authentication
Аутентификация — это процесс, при котором клиент должен доказать серверу, что что он именно тот, за кого себя выдаёт.
Например, после создания EKS мы поднимаем рабочие ноды, которые затем обращаются к API-серверу Kubernetes Control Plane, что бы подключиться к кластеру.
При этом — API-сервер должен иметь возможность проверить — что за клиент к нему обратился, и имеет ли он вообще право к нам обращаться.
Для этого у Kubernetes имеются authentication modules или authenticators: когде API-сервер получается запрос от клиента, будь то новая Worker Node, kubelet или просто API-запрос, отправленный curl-ом — он обращается к одному из настроенных у Kubernetes аутентификаторов и запускает процесс аутентификации клиента, отправившего запрос.
Все доступные модули можно увидеть в документации, но нас сейчас интересует один, использующийся в AWS Elatic Kubernetes Service — aws-iam-authenticator для проверки валидности пользователя, используя сервис AWS IAM, который мы будем рассматривать ниже.
Authorization
После того, как пользователь прошёл аутентификацию, Kubernetes должен проверить сам запрос — есть ли у данного клиента право на выполнение запрошенных действий, например — выполнение вызова kubectl get pods.
Если вспомнить IAM-политики, то в них мы явно описываем права на конкретные сервисы и действия, например:
Тут в Action указаны действия, разрешённые пользователю, к которому эта политика подключена, и при вызове им операции «s3:DeleteObject» — пользователь получит отказ на выполнение действия, т.е. проверяется контроль доступа к API-вызовам (а вся работа с AWS, как и с Kubernetes, выполняется через API-вызовы к ядру AWS).
Модулю авторизации передаётся пользователь, прошедший аутентификацию, после чего он проходит авторизацию, на основании которой API-сервер принимает решение о выполнении действия — или отказе.
Далее рассмотрим весь процесс аутентификации и авторизации в AWS EKS, а потом перейдём к авторизации.
AWS EKS Authentication и Authorization
Всю процедуру отлично демонстрирует следующая схема:
AWS EKS IAM Authentication
Для аутентификации EKS использует токены — см. Webhook Token Authentication: клиент передаёт API-серверу специально сформированный токен аутентификации, в котором среди прочих данных передаётся идентификатор пользователя.
В случае с EKS — этим идентификатором могут являться ARN (Amazon Resource Name) либо IAM-пользователя, либо IAM-роли.
Kubrnetes-аутентификатор в свою очередь передаёт извлечённый идентификатор самому AWS IAM для проверки — есть ли такой, и имеет ли право говорить с нами, а в роли аутентификатора в Kubernetes использует AWS IAM Authenticator.
Т.е. процесс выглядит следующим образом:
клиент выполняет запрос к API-серверу, передавая токен аутентификации, в котором включён ID пользователя
API-сервер передаёт токен другому сервису Kubernetes Control Plane — aws-iam-authenticator
aws-iam-authenticator обращается к AWS IAM, передавая этого пользователя для проверки — имеется ли такой IAM-идентификатор (ARN) и имеет ли он право доступа к запрашиваемому EKS-кластеру
у себя AWS проводит собственную аутентификацию, используя секретный ключ, связанный с предоставленным ACCESS_ID,
и проводит собственную авторизацию на соответствие политикам, подключенным к этом пользователю — пользователь без прав на API-вызовы к eks::* должен быть отвергнут
aws-iam-authenticator обращается к Kubernetes, проверяя у него (через aws-auth ConfigMap, будет в AWS EKS aws-auth ConfigMap) — имеет ли этот IAM-индентификатор право на доступ к кластеру
aws-iam-authenticator возвращает ответ валиден или нет клиент API-серверу
API-сервер отвечает клиенту ответом с данными, либо сообщает You must be logged in to the server (Unauthorized) и отвергает запрос
При этом сам aws-iam-authenticator может использоваться как на сервере — так и на клиенте, только на сервере он запускается как aws-iam-authenticator server, а на клиенте — aws-iam-authenticator token -i:
Но в моём случае клиент настраивался через aws eks update-kubeconfig и использует AWS CLI вместо вызова aws-iam-authenticator (см. AWS CLI vs aws-iam-authenticator).
Аутентификация kubectl
Используем kubectl на локальной машине в роли клиента, и посмотрим всю цепочку сами.
Итак, kubectl обращается к локальному файлу ~/.kube/config, из которого получает URL API-сервера EKS-кластера, к которому ему следует обращаться:
Которая собственно и описывает команду для получения токена для аутентификации в EKS, в котором используется AWS CLI — aws eks get-token.
Очень хочется покопаться в аутентификации самого AWS API, например быстро нагугленные решения есть в Developer Guide для AWS S3, если будет время — можно будет попробовать сделать всю работу просто используя curl, т.к. под капотом AWS CLI точно так же обращается к AWS по API, как наш kubectl — к API-серверу Kubernets.
Вызываем команду из command, передавая аргументы из args:
В поле Amz-Credential=AKI***D4Q как раз передаётся ACCESS_KEY нашего пользователя из профиля AWS CLI arseniy (про профили поговорим совсем скоро в в AWS профили):
cat ~/.aws/credentials | grep -B1 -A2 AKI***D4Q
[arseniy]
aws_access_key_id = AKI***D4Q
aws_secret_access_key = q0I***jvj
Итак:
передаём ACCESS_KEY
используя ACCESS_KEY — получаем ARN пользователя
используя ARN, aws-iam-authenticator на EKS Control Plane проверяет — разрешён ли пользователю доступ к кластеру (см. AWS EKS aws-auth ConfigMap)
Проверим наш ключ:
aws --profile arseniy iam list-access-keys --user-name arseniy
Т.е. тут мы видим, что kubectl просто получает токен, используя один из доступных ему методов, заданных через ~/.kube/conf — либо используя AWS CLI (вызывая /usr/bin/aws), либо с помощью /usr/bin/aws-iam-authenticator.
AWS профили
Давайте рассмотрим ещё одну часть файла ~/.kube/config, а именно — env:
Точно так же сам kubectl выполняет API-запросы к Kubernetes.
Кстати — все эти запросы можно посмотреть в CloudWatch Logs, если вы включили их при создании или в настройках кластера, например логи аутентификации — в логах, внезапно, authentificator-***:
heptio-authenticator-aws vs aws-iam-authenticator
Сначала удивился, почему в логих виден heptio-authenticator-aws, если в документации AWS говорится про aws-iam-authenticator? См. Managing Cluster Authentication.
Но всё оказалось просто: до версии 4.0 aws-iam-authenticator назывался heptio-authenticator-aws.
Хорошо — тут мы разобрались. А что происходит дальше?
AWS EKS aws-auth ConfigMap
Собственно, тут и начинается «магия» аутентификации — теперь aws-iam-authenticator должен:
проверить у самого AWS IAM — есть ли запрошенный пользователь в системе, и имеет ли он права, т.е. выполнить его аутентифицакию
передать его API-серверу Kubernetes, после чего тот выполнит авторизацию — проверит, имеет ли этот пользоваль право доступа к кластеру, и тут как раз используется aws-auth ConfigMap
Где в строке arn:aws:iam::534***385:role/mobilebackend-dev-eks-0-wn-stack-NodeInstanceRole-15NNFZK6WW4IG мы передаём ARN роли, которой разрешён доступ к кластеру. Группы обсудим в Авторизации, в следующей части.
Добавление пользователя к кластеру
И вернёмся к вопросу — почему другой IAM-пользователь получает сообщение «You must be logged in to the server (Unauthorized)«?
Собственно, ответ явно виден выше — потому что его нет в нашем ConfigMap.
Готово — теперь arn:aws:iam::534***385:user/yaroslav может выполнять любые операции на сервере.
«root» aka Cluster creator
Последний нюанс во всей этой схеме, это факт того, что вы никак не можете увидеть создателя кластера, из-за чего, собственно, и возникло непонимание: пользователь arn:aws:iam::534***385:user/arseniy имел полный доступ к системе, а arn:aws:iam::534***385:user/yaroslav — нет.
Причём найти «создателя» пока удалось только в CloudTrail по API-вызову к AWS — CreateCluster :
Возникает она потому что:
The IAM identity that created the EKS cluster is automatically “hardwired” in the AWS IAM Authenticator. This means that this IAM identity is recognised and authenticated (and mapped to a user in the system:masters group) by the AWS IAM Authenticator without being listed in the aws-auth ConfigMap.
И при этом никакой возможности увидеть её где-то «внутри» самого EKS вроде как нет (но я написал в саппорт — может подскажут).
UPD 02.09.2019
Пришёл ответ от саппорта — всё-таки увидеть нельзя:
At this time, the IAM entity that creates the cluster becomes the first cluster administrator. This entity is passed to
the master nodes and is not visible from the `aws-auth` ConfigMap. This is similar to the root user for your AWS account
in that it has the system:masters permission.