Ще одна крута фіча, яку Амазон показав ще на минулому re:Invent в листопаді 2023 – це зміни в тому, як AWS Elastic Kubernetes Service виконує аутентифікацію та авторизацію юзерів. При чому це стосується не тільки саме користувачів кластеру, а і WorkerNodes.
Тобто, не дуже-то нова схема – але в мене ось тільки зараз дійшли руки до апгрейду кластеру з 1.28 на 1.30, заодно буду оновлювати версію модулю terraform-aws-modules/eks
зі змінами ESK Access Management API, бо зараз ми на версії 19, а зміни були додані в версії 20 (див. v20.0.0 Release notes),
Про Terraform, мабуть, поговоримо в наступному пості, а сьогодні давайте глянемо як нова система працює, і що вона нам дозволяє. А вже знаючи це – візьмемо Terraform, і взагалі подумаємо про те, як організувати роботу з IAM з урахування змін в EKS Access Management API та EKS Pod Identities.
Загалом по аутентифікації/авторизації в Kubernetes можна ще глянути старі пости:
- Kubernetes: знакомство, часть 4 – аутентификация в AWS EKS, aws-iam-authenticator и AWS IAM
- AWS Elastic Kubernetes Service: RBAC-авторизация через AWS IAM и RBAC группы
- AWS: EKS, OpenID Connect та ServiceAccounts
Зміст
Як це працює?
Раніше ми мали спеціальний aws-auth
ConfigMap, в якому описувались WorkerNodes IAM Roles, всі наші юзери та їхні групи.
Відтепер, ми можемо керувати доступами в EKS напряму через його API використовуючи AWS IAM в ролі аутентифікатора. Тобто, юзер логіниться в AWS, AWS виконує аутентифікацію – перевіряє, що це саме той юзер, за якого він себе видає, а потім, коли юзер підключається до Kubernetes – то виконується його авторизація – перевірка прав доступу до кластеру і в самому кластері.
При цьому ця схема чудово працює з RBAC самого Kubernetes.
І ще одна дуже важлива деталь – що ми нарешті можемо позбутись “дефолтного root-юзера” – прихованого адміністратора кластера, від імені якого він створювався. При чому раніше ми не мали змоги ніде його побачити або змінити, що іноді спричиняло проблеми.
Отже, якщо раніше нам потрібно було самим керувати записами в aws-auth
ConfigMap, і не дай боже його зламати (а в мене траплялось через чи то кривий маніфест, чи то не дуже прямі руки) – то тепер ми можемо винести управління доступами в окремий Terraform-код, і управляти доступами набагато простіше і з меншим ризиком.
Зміни в IAM та EKS
Тепер у нас в EKS є дві нові сутності – Access entries та Access policies:
- Amazon EKS Access Entries – запис в EKS про об’єкт, який пов’язаний з AWS IAM роллю чи юзером
- описує тип (звичайний юзер, EC2, etc), Kubernetes RBAC Groups, або EKS Access Policy
- Amazon EKS Access Policy – політика в EKS, яка описує права для EKS Access Entries. І це політики саме EKS – ви не знайдете їх в IAM.
Наразі є 4 EKS Access Policy, які ми можемо використати, і вони аналогічні дефолтним User-facing ClusterRoles в Kubernetes :
AmazonEKSClusterAdminPolicy
– cluster-adminAmazonEKSAdminPolicy
– adminAmazonEKSEditPolicy
– editAmazonEKSViewPolicy
– view
Підозрюю, що десь під капотом ці EKS Access Policy просто мапляться на Kubernetes ClusterRoles.
Ці політики ми підключаємо до IAM Role чи IAM user, і під час підключення до Kubernetes-кластеру EKS Autorizer перевіряє які саме права є у цього користувача.
Схематично це можна відобразити так:
Або така схема, з блогу AWS A deep dive into simplified Amazon EKS access management controls:
Замість дефолтних AWS managed IAM Policy ми при створенні EKS Access Policy можемо вказати ім’я Kubernetes RBAC Group – і тоді замість EKS Autorizer буде використано механізм Kubernetes RBAC – далі подивимось, як це працює.
Для Terraform в terraform-provider-aws версії 5.33.0 були додані два нових відповідних типи resource – aws_eks_access_entry
та aws_eks_access_policy_association
. Але зараз все будемо робити руками.
Налаштування Cluster access management API
Перевіряти як воно працює будемо на існуючому кластері версії 1.28.
Відкриваємо налаштування кластера, вкладка Access, клікаємо Manage access:
Зараз у нас включено ConfigMap (той самий aws-auth
) – міняємо на EKS API and ConfigMap – так ми залишимо і старий механізм, і протестуємо новий (в Terraform це також можна зробити):
Звертаємо увагу на попередження “Once you modify a cluster to use EKS access entry API, you cannot change it back to ConfigMap only” – але terraform-aws-modules/eks
версії 19.21 ці зміни ігнорує і нормально працює далі, тож можна міняти руками.
Тепер кластер буде виконувати авторизацію юзерів і з aws-auth
ConfigMap, і з EKS Access Entry API, з перевагою до Access Entry API.
Після переключення на EKS Access Entry API відразу маємо нові EKS Access Entries:
І як раз тепер ми можемо побачити того самого “прихованого root-юзера” – assumed-role/tf-admin
, бо Teraform працює саме від цієї IAM-ролі, і в моєму сетапі це робилось як через цей механізм EKS, від якого тепер можна буде позбутись.
Але з поточного aws-auth
ConfigMap взято не все – роль для WorkerNodes є, а от решта записів (юзери з mapUsers
та ролі з mapRoles
) автоматично не додались. Хоча під час зміни параметра API_AND_CONFIG_MAP
через Teraform це наче має відбутись – потім перевіримо.
Підключення нового IAM User до кластеру EKS
Перевірити існуючі EKS Access Entries з AWS CLI можна командою aws eks list-access-entries
:
$ aws --profile work eks list-access-entries --cluster-name atlas-eks-test-1-28-cluster { "accessEntries": [ "arn:aws:iam::492***148:role/test-1-28-default-eks-node-group-20240702094849283200000002", "arn:aws:iam::492***148:role/tf-admin" ] }
Давайте додамо нового IAM User з доступом до кластеру.
Створюємо юзера:
В Set permissions не вибираємо нічого, просто клікаємо Next:
Створюємо Access Key – будемо використовувати цього юзера з AWS CLI, аби згенерувати kubectl config:
Додаємо дозвіл на eks:DescribeCluster
:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Statement1", "Effect": "Allow", "Action": ["eks:DescribeCluster"], "Resource": ["*"] } ] }
Зберігаємо, і створюємо новий AWS CLI профайл:
$ vim -p ~/.aws/config ~/.aws/credentials
Додаємо профайл до ~/.aws/config
:
[profile test-eks] region = us-east-1 output = json
І ключі до ~/.aws/credentials
:
[test-eks] aws_access_key_id = AKI***IMN aws_secret_access_key = Kdh***7wP
Створюємо новий kubectl context
:
$ aws --profile test-eks eks update-kubeconfig --name atlas-eks-test-1-28-cluster --alias test-cluster-test-user Updated context test-cluster-test-user in /home/setevoy/.kube/config
З юзером закінчили – тепер треба з ним підключитись до кластеру.
EKS: створення Access Entry
Можемо зробити або через AWS Console:
Або з AWS CLI (з робочим профайлом, а не новим, бо в нього ніяких прав нема) і командою aws eks create-access-entry
.
В параметрах передаємо ім’я кластера та ARN юзера чи ролі, яких підключаємо до кластеру (але, мабуть, більш коректно буде сказати “для яких створюємо точку входу на кластер“, бо сутність називається Access Entry):
$ aws --profile work eks create-access-entry --cluster-name atlas-eks-test-1-28-cluster --principal-arn arn:aws:iam::492***148:user/test-eks-acess-TO-DEL { "accessEntry": { "clusterName": "atlas-eks-test-1-28-cluster", "principalArn": "arn:aws:iam::492***148:user/test-eks-acess-TO-DEL", "kubernetesGroups": [], "accessEntryArn": "arn:aws:eks:us-east-1:492***148:access-entry/atlas-eks-test-1-28-cluster/user/492***148/test-eks-acess-TO-DEL/98c8398d-9494-c9f3-2bfc-86e07086c655", ... "username": "arn:aws:iam::492***148:user/test-eks-acess-TO-DEL", "type": "STANDARD" } }
Ще раз глянемо в AWS Console:
Новий Enrty додано, йдемо далі.
Підключення EKS Access Policy
Зараз доступу до кластеру з новим юзером ми все ще не маємо, бо до нього не підключена політика – поле Access policies пусте.
Перевіряємо з kubectl auth can-i
:
$ kubectl auth can-i get pod no
Додати EKS Access Policy можемо або в AWS Console:
Або знов-таки з AWS CLI і командою aws eks associate-access-policy
.
Давайте поки додамо AmazonEKSViewPolicy
:
$ aws --profile work eks associate-access-policy --cluster-name atlas-eks-test-1-28-cluster \ > --principal-arn arn:aws:iam::492***148:user/test-eks-acess-TO-DEL \ > --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy \ > --access-scope type=cluster { "clusterName": "atlas-eks-test-1-28-cluster", "principalArn": "arn:aws:iam::492***148:user/test-eks-acess-TO-DEL", "associatedAccessPolicy": { "policyArn": "arn:aws:eks::aws:cluster-access-policy/AmazonEKSViewPolicy", "accessScope": { "type": "cluster", "namespaces": [] }, ... }
Зверніть увагу на --access-scope type=cluster
– зараз ми видали ReadOnly права на весь кластер, але можемо обмежити конкретним неймспейсом(ми) – далі спробуємо.
Глянемо ще раз в AWS Console:
Access Policy додано.
Пробуємо kubectl
:
$ kubectl auth can-i get pod yes
Але не можемо створити под – бо маємо ReadOnly права:
$ kubectl auth can-i create pod no
Інші корисні команди для AWS CLI:
Видалення default root user
На майбутнє, відключити створення такого юзеру при створенні кластера з aws eks create-cluster
можна параметром bootstrapClusterCreatorAdminPermissions=false
.
А зараз давайте замінимо його – додамо нашому тестовому юзеру адмін-права і видалимо дефолтного root.
Повторяємо aws eks associate-access-policy
, але тепер в --policy-arn
вказуємо AmazonEKSClusterAdminPolicy
:
$ aws --profile work eks associate-access-policy --cluster-name atlas-eks-test-1-28-cluster \ > --principal-arn arn:aws:iam::492***148:user/test-eks-acess-TO-DEL \ > --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy \ > --access-scope type=cluster
І що з правами тепер?
$ kubectl auth can-i create pod yes
Тепер маємо двох cluster-admin:
І можемо видалити старого:
$ aws --profile work eks delete-access-entry --cluster-name atlas-eks-test-1-28-cluster --principal-arn arn:aws:iam::492***148:role/tf-admin
Namespaced EKS Access Entry
Замість того, аби видавати права на весь кластер з --access-scope type=cluster
– ми можемо зробити юзера адміном тільки у конкретних неймспейсах.
Не відключаємо нашого тестового юзера – бо наразі це наш єдиний адмін. Давайте візьмемо звичайного IAM User, то зробимо його адміном тільки в одному Kubernetes Namespace.
Створюємо новий неймспейс:
$ kk create ns test-ns namespace/test-ns created
Створюємо нову EKS Access Entry для мого AWS IAM User:
$ aws --profile work eks create-access-entry --cluster-name atlas-eks-test-1-28-cluster --principal-arn arn:aws:iam::492***148:user/arseny
І підключаємо AmazonEKSEditPolicy
, але в --access-scope
задаємо тип namespace
та вказуємо ім’я цього NS:
$ aws --profile work eks associate-access-policy --cluster-name atlas-eks-test-1-28-cluster \ > --principal-arn arn:aws:iam::492***148:user/arseny \ > --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSEditPolicy \ > --access-scope type=namespace,namespaces=test-ns
В access-scope
ми можемо задати або clutser
, або неймспейс. Не дуже гнучко – але для гнучкості у нас є RBAC.
Генеруємо новий kubectl context
з --profile work
, де profile work – мій звичайний AWS User, для якого ми створювали EKS Access Entry з AmazonEKSEditPolicy
:
$ aws --profile work eks update-kubeconfig --name atlas-eks-test-1-28-cluster --alias test-cluster-arseny-user Updated context test-cluster-arseny-user in /home/setevoy/.kube/config
Перевіряємо активний kubectl context
:
$ kubectl config current-context test-cluster-arseny-user
І перевіряємо права – спочатку в default Namespace:
$ kubectl --namespace default auth can-i create pod no
І в тестовому неймспейсі:
$ kubectl --namespace test-ns auth can-i create pod yes
Nice!
Все працює.
EKS Access Entry та Kubernetes RBAC
Замість того, щоб підключати EKS Access Policy від AWS, яких всього чотири – ми можемо використати звичайний механізм Kubernetes Role-Based Access Control, RBAC.
Це виглядає так:
- в EKS створюємо Access Entry
- в параметрах Access Entry вказуємо Kubernetes RBAC Group
- а далі за звичною схемою – використовуємо RBAC Group та Kubernetes RoleBinding
Тоді ми пройдемо аутентифікацію в AWS, після чого AWS “передасть” нас до Kubernetes, а той вже виконає авторизацію – перевірку наших прав в кластері – на основі нашої RBAC-групи.
Видаляємо створену Access Entry для мого IAM User:
$ aws --profile work eks delete-access-entry --cluster-name atlas-eks-test-1-28-cluster --principal-arn arn:aws:iam::492***148:user/arseny
Створюємо його заново, але тепер додаємо --kubernetes-groups
:
$ aws --profile work eks create-access-entry --cluster-name atlas-eks-test-1-28-cluster \ > --principal-arn arn:aws:iam::492***148:user/arseny \ > --kubernetes-groups test-eks-rbac-group
Глянемо в AWS Console:
Пробуємо перевірити права з kubectl
:
$ kubectl --namespace test-ns auth can-i create pod no
Бо EKS Access Policy ми не додавали, і в RBAC нічого не робили.
Опишемо RoleBinding та зв’яжемо RBAC групу test-eks-rbac-group
з дефолтною Kubernetes edit
ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: test-eks-rbac-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: edit subjects: - apiGroup: rbac.authorization.k8s.io kind: Group name: test-eks-rbac-group
Переключаємо контекст на нашого адміна (я для цього користуюсь kubectx
):
$ kx ✔ Switched to context "test-cluster-test-user".
І створюємо RoleBinding в неймспейсі test-ns
, аби дати юзеру права Edit тільки в цьому NS:
$ kubectl --namespace test-ns apply -f test-rbac.yml rolebinding.rbac.authorization.k8s.io/test-eks-rbac-binding created
Переключаємось на юзера arseny:
$ kx ✔ Switched to context "test-cluster-arseny-user".
І знову перевіряємо права в двох неймспейсах:
$ kubectl --namespace default auth can-i create pod no $ kubectl --namespace test-ns auth can-i create pod yes
RBAC працює.
Ну і в принципі на цьому все.
Механізм працює, основні його сутності в роботі побачили – тепер можна переходити до Terraform.