
Инструмент для использования учетных данных AWS IAM для аутентификации в кластере Kubernetes
# AWS IAM Authenticator для Kubernetes
Инструмент для использования учётных данных AWS IAM при аутентификации в кластере Kubernetes.
Начальная работа над этим инструментом велась под руководством Heptio. Проект получает вклад от множества инженеров сообщества и в настоящее время поддерживается инженерами Heptio и Amazon EKS OSS.
## Содержание
- [Зачем мне это нужно?](#why-do-i-want-this)
- [Как это использовать?](#how-do-i-use-it)
- [Использование с Kops](#kops-usage)
- [Как это работает?](#how-does-it-work)
- [Что такое cluster ID?](#what-is-a-cluster-id)
- [Указание учётных данных и использование профилей AWS](#specifying-credentials--using-aws-profiles)
- [Авторизация API извне кластера](#api-authorization-from-outside-a-cluster)
- [Устранение неполадок](#troubleshooting)
- [Полный формат конфигурации](#full-configuration-format)
- [Разработка](#development)
- [Сообщество, обсуждение, вклад и поддержка](#community-discussion-contribution-and-support)
## Зачем мне это нужно?
Если вы администратор, запускающий кластер Kubernetes на AWS, вам уже необходимо управлять учётными данными AWS IAM для развёртывания и обновления кластера.
Используя AWS IAM Authenticator для Kubernetes, вы избегаете необходимости управлять отдельными учётными данными для доступа к Kubernetes.
AWS IAM также предоставляет ряд полезных свойств, таких как независимый от основного канала аудит (через CloudTrail) и принудительное использование 2FA/MFA.
Если вы создаёте установщик Kubernetes на AWS, AWS IAM Authenticator для Kubernetes может упростить процесс начальной загрузки.
Вам не потребуется каким-либо образом безопасно передавать ваши первоначальные учётные данные администратора за пределы только что установленного кластера.
Вместо этого вы можете создать выделенную роль `KubernetesAdmin` во время развёртывания кластера и настроить Authenticator для разрешения входа администраторов кластера.
## Как это использовать?
Предполагая, что у вас есть кластер, работающий в AWS, и вы хотите добавить поддержку AWS IAM Authenticator для Kubernetes, вам необходимо:
1. Создать роль IAM, которую вы будете использовать для идентификации пользователей.
2. Запустить сервер Authenticator как DaemonSet.
3. Настроить ваш API-сервер для взаимодействия с Authenticator.
4. Настроить kubectl для использования токенов Authenticator.
### 1. Создание роли IAM
Сначала вы должны создать одну или несколько ролей IAM, которые будут сопоставлены пользователям/группам внутри вашего кластера Kubernetes.
Проще всего это сделать, войдя в консоль AWS:
- Выберите опцию "Role for cross-account access" / "Provide access between AWS accounts you own".
- Вставьте номер вашего аккаунта AWS (доступен в правом верхнем углу консоли).
- Вашей роли не нужно прикреплять какие-либо дополнительные политики.
Это создаст роль IAM без разрешений, которую могут принимать авторизованные пользователи/роли в вашем аккаунте.
Запомните Amazon Resource Name (ARN) вашей роли, он понадобится вам ниже.
Вы также можете сделать это за один шаг, используя AWS CLI вместо консоли AWS:
```sh
# get your account ID
ACCOUNT_ID=$(aws sts get-caller-identity --output text --query 'Account')
# define a role trust policy that opens the role to users in your account (limited by IAM policy)
POLICY=$(echo -n '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::'; echo -n "$ACCOUNT_ID"; echo -n ':root"},"Action":"sts:AssumeRole","Condition":{}}]}')
# create a role named KubernetesAdmin (will print the new role's ARN)
aws iam create-role \
--role-name KubernetesAdmin \
--description "Kubernetes administrator role (for AWS IAM Authenticator for Kubernetes)." \
--assume-role-policy-document "$POLICY" \
--output text \
--query 'Role.Arn'
```
Вы также можете пропустить этот шаг и использовать:
- Существующую роль (например, роль доступа между аккаунтами).
- Пользователя IAM (см. `mapUsers` ниже).
- Экземпляр EC2 или федеративную роль (см. `mapRoles` ниже).
### 2. Запустите сервер
Сервер предназначен для запуска на каждом из ваших master-узлов в виде DaemonSet с сетью хоста, чтобы он мог открывать порт localhost.
Пример конфигурации ConfigMap и DaemonSet см. в [`deploy/example.yaml`](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/deploy/example.yaml).
Перед применением обновите следующие значения для вашего кластера:
- Замените заполнители IAM ARN (`arn:aws:iam::000000000000:...`) в `config.yaml`.
- Задайте `clusterID` уникальное значение для вашего кластера.
- Убедитесь, что правила планирования DaemonSet соответствуют меткам/taints ваших узлов control-plane.
Затем разверните его:
```sh
kubectl apply -f deploy/example.yaml
kubectl -n kube-system rollout status daemonset/aws-iam-authenticator
kubectl -n kube-system get pods -l k8s-app=aws-iam-authenticator
```
После запуска пода на узле control-plane `aws-iam-authenticator server` создаст webhook kubeconfig на хосте по пути `/etc/kubernetes/aws-iam-authenticator/kubeconfig.yaml` (или по пути, заданному через `--generate-kubeconfig`).
#### (Необязательно) Предварительная генерация сертификата, ключа и kubeconfig
Если вы создаёте автоматизированный установщик, вы также можете легко предварительно сгенерировать файлы сертификата, ключа и webhook kubeconfig с помощью `aws-iam-authenticator init`.
Эта команда сгенерирует файлы и разместит их в настроенных выходных каталогах.
Вы можете запустить её на каждом master-узле перед запуском API-сервера.
Вы также можете сгенерировать их до провижининга master-узлов и установить в соответствующие пути на хостах.
Если вы не генерируете файлы заранее, `aws-iam-authenticator server` сгенерирует их по требованию.
Это работает, но требует перезапуска вашего Kubernetes API-сервера после установки.
### 3. Настройте ваш API-сервер для взаимодействия с сервером
Kubernetes API интегрируется с AWS IAM Authenticator for Kubernetes с помощью [webhook аутентификации по токену](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication).
При запуске `aws-iam-authenticator server` он сгенерирует файл конфигурации webhook и сохранит его в файловой системе хоста.
Вам нужно будет добавить один дополнительный флаг в конфигурацию вашего API-сервера:
```
--authentication-token-webhook-config-file=/etc/kubernetes/aws-iam-authenticator/kubeconfig.yaml
```
На многих кластерах API-сервер работает как статический pod.
Вы можете добавить флаг в `/etc/kubernetes/manifests/kube-apiserver.yaml`.
Убедитесь, что каталог хоста `/etc/kubernetes/aws-iam-authenticator/` смонтирован в pod вашего API-сервера.
Также может потребоваться перезапустить демон kubelet на вашем master-узле, чтобы применить обновлённое определение статического pod:
```
systemctl restart kubelet.service
```
### 4. Создание сопоставлений ролей/пользователей IAM с пользователями/группами Kubernetes
По умолчанию сервер берёт сопоставления исключительно из полей
`mapUsers` и `mapRoles` своего файла конфигурации. Подробности см. в разделе [Полный
формат конфигурации](#full-configuration-format) ниже.
С помощью флага `--backend-mode` можно настроить сервер так, чтобы он брал
сопоставления из двух дополнительных бэкендов: ConfigMap в стиле EKS
(`--backend-mode=EKSConfigMap`) или пользовательских ресурсов `IAMIdentityMapping`
(`--backend-mode=CRD`). Бэкенд по умолчанию — файл конфигурации сервера,
монтируемый в под сервера, — соответствует `--backend-mode=MountedFile`.
Можно передать список этих бэкендов через запятую, чтобы сервер искал
их по порядку. Например, с `--backend-mode=EKSConfigMap,MountedFile` сервер
сначала будет искать сопоставления в ConfigMap в стиле EKS, а затем, если не
найдёт сопоставление для заданной роли/пользователя IAM, — в файле конфигурации
сервера. Если сопоставление для одной и той же роли/пользователя IAM существует
в нескольких бэкендах, сервер будет использовать сопоставление из бэкенда,
который идёт первым в списке через запятую. В этом примере, если сопоставление
найдено в ConfigMap EKS, то оно будет использовано независимо от того, существует
ли дублирующее или конфликтующее сопоставление в файле конфигурации сервера.
Обратите внимание: если задан один бэкенд, сервер будет брать данные *только*
из него и игнорировать остальные, даже если они существуют. Например, с
`--backend-mode=CRD` сервер будет брать данные *только* из `IAMIdentityMappings`
и игнорировать смонтированный файл и ConfigMap EKS.
#### `MountedFile`
Это бэкенд сопоставлений по умолчанию, и его достаточно для большинства пользователей. Подробности см.
в разделе [Полный формат конфигурации](#full-configuration-format) ниже.
#### `CRD` (alpha)
Этот бэкенд моделирует каждое сопоставление IAM как [пользовательский
ресурс Kubernetes](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)
`IAMIdentityMapping`. Этот подход позволяет поддерживать сопоставления
в Kubernetes-нативном виде с помощью kubectl или API. Кроме того, синтаксические
ошибки (например, нарушенные отступы YAML) легче обнаружить, и они не затрагивают
все сопоставления.
Чтобы настроить CRD `IAMIdentityMapping`, сначала нужно применить (`apply`)
манифест CRD:
```
kubectl apply -f deploy/iamidentitymapping.yaml
```
После развёртывания CRD вы можете создавать пользовательские ресурсы, которые моделируют ваши
IAM-идентичности. См.
[`./deploy/example-iamidentitymapping.yaml`](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/deploy/example-iamidentitymapping.yaml):
```
---
apiVersion: iamauthenticator.k8s.aws/v1alpha1
kind: IAMIdentityMapping
metadata:
name: kubernetes-admin
spec:
# Arn of the User or Role to be allowed to authenticate
arn: arn:aws:iam::XXXXXXXXXXXX:user/KubernetesAdmin
# Username that Kubernetes will see the user as, this is useful for setting
# up allowed specific permissions for different users
username: kubernetes-admin
# Groups to be attached to your users/roles. For example `system:masters` to
# create cluster admin, or `system:nodes`, `system:bootstrappers` for nodes to
# access the API server.
groups:
- system:masters
```
#### `EKSConfigMap`
В качестве бэкенда используется ConfigMap `kube-system/aws-auth` в стиле EKS. Ожидается, что
ConfigMap будет в точно таком же формате, как в кластерах EKS:
https://docs.aws.amazon.com/eks/latest/userguide/add-user-role.html. Это
полезно, если вы мигрируете из EKS или в EKS и хотите сохранить свои маппинги, или
запускаете EKS в дополнение к некоторым другим кластерам AWS и хотите иметь одинаковые
маппинги в каждом из них.
#### `DynamicFile`
В качестве бэкенда может служить локальный файл, указанный в cfg.dynamicfilepath. Ожидается, что содержимое файла
будет в точно таком же формате, как у EKSConfigMap. Всякий раз, когда
содержимое этого файла изменяется, authenticator автоматически перезагрузит его. Это
обеспечивает большую гибкость при управлении маппингами ARN.
См. https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/hack/dev/authenticator_with_dynamicfile_mode.yaml
о том, как настроить режим DynamicFile.
Запустите `make e2e RUNNER=kind`, чтобы поработать с кластером kind с включённым режимом DynamicFile.
### 5. Как настроить reservedPrefixConfig для имён пользователей Kubernetes
aws-iam-authenticator может поддерживать зарезервированный префикс для имени пользователя k8s. Если зарезервированный префикс
задан, то имя пользователя с зарезервированным префиксом не будет аутентифицировано с ошибкой
"username must not begin with with the following prefixes:".
См. https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/master/hack/dev/authenticator_with_dynamicfile_mode.yaml
о том, как настроить зарезервированный префикс.
### 6. Настройка kubectl для использования токенов аутентификации, предоставляемых AWS IAM Authenticator for Kubernetes
Наконец, после того как сервер настроен, вы захотите пройти аутентификацию.
Вам по-прежнему понадобится `kubeconfig`, содержащий публичные данные о вашем кластере (сертификат CA кластера, адрес эндпоинта).
Однако раздел `users` вашей конфигурации должен включать секцию exec ([см. документацию по плагинам учётных данных kubectl](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins)):
```yaml
# [...]
users:
- name: kubernetes-admin
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws-iam-authenticator
args:
- "token"
- "-i"
- "REPLACE_ME_WITH_YOUR_CLUSTER_ID"
- "-r"
- "REPLACE_ME_WITH_YOUR_ROLE_ARN"
# no client certificate/key needed here!
```
Это означает, что `kubeconfig` полностью является публичными данными и может быть передан всем пользователям Authenticator.
Может иметь смысл загрузить его в доверенное публичное место, например в AWS S3.
Убедитесь, что у вас установлен бинарный файл `aws-iam-authenticator`.
Вы можете установить его с помощью `go install sigs.k8s.io/aws-iam-authenticator/cmd/aws-iam-authenticator@latest`.
Для аутентификации выполните `kubectl --kubeconfig /path/to/kubeconfig" [...]`.
kubectl выполнит `exec` бинарного файла `aws-iam-authenticator` с указанными параметрами в вашем kubeconfig, который сгенерирует токен и передаст его apiserver.
Токен действителен в течение 15 минут (наименьшее значение, разрешённое AWS) и может быть использован повторно несколько раз.
Вы также можете указать имя сессии при генерации токена, включив параметр `--session-name` или `-s`. Этот параметр нельзя использовать вместе с `--forward-session-name`.
Вы также можете опустить `-r ROLE_ARN`, чтобы подписать токен вашими существующими учётными данными без принятия выделенной роли.
Это полезно, если вы хотите аутентифицироваться напрямую как пользователь IAM или если вы хотите аутентифицироваться с использованием роли экземпляра EC2 или федеративной роли.
## Использование с Kops
Кластеры, управляемые [Kops](https://github.com/kubernetes/kops), можно настроить для использования Authenticator. Инструкции по использованию см. в [документации Kops](https://kops.sigs.k8s.io/authentication/#aws-iam-authenticator).
## Как это работает?
Это работает с использованием конечной точки API AWS [`sts:GetCallerIdentity`](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html).
Эта конечная точка возвращает информацию о любых учётных данных AWS IAM, которые вы используете для подключения к ней.
#### Сторона клиента (`aws-iam-authenticator token`)
Мы используем этот API несколько необычным образом: клиент Authenticator генерирует и предварительно подписывает запрос к конечной точке.
Мы сериализуем этот запрос в токен, который может пройти через систему аутентификации Kubernetes.
#### Сторона сервера (`aws-iam-authenticator server`)
Токен проходит через API-сервер Kubernetes и попадает в конечную точку `/authenticate` сервера Authenticator через конфигурацию webhook.
Сервер Authenticator проверяет все параметры предварительно подписанного запроса, чтобы убедиться, что ничего не выглядит подозрительно.
Затем он отправляет запрос на реальный сервер `https://sts.amazonaws.com`, который проверяет HMAC-подпись клиента и возвращает информацию о пользователе.
Теперь, когда сервер знает идентичность AWS клиента, он преобразует эту идентичность в пользователя и группы Kubernetes с помощью простого статического сопоставления.
Этот механизм заимствован с небольшими изменениями из [Vault](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method).
## Что такое cluster ID?
Cluster ID Authenticator — это уникальный для каждого кластера идентификатор, который предотвращает определённые атаки повторного воспроизведения.
В частности, он не позволяет одному серверу Authenticator (например, в среде разработки) использовать токен клиента для аутентификации на другом сервере Authenticator в другом кластере.
Cluster ID должен быть уникальным для каждого кластера, но он не обязан быть секретным.
Некоторые хорошие варианты:
- Случайный ID, например полученный с помощью `openssl rand 16 -hex`
- Доменное имя вашего API-сервера Kubernetes
[Документация Vault](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method) также объясняет эту атаку (см. `X-Vault-AWS-IAM-Server-ID`).
## Указание учётных данных и использование профилей AWS
Учётные данные могут быть указаны для использования с `aws-iam-authenticator` любым из методов, доступных в
[AWS SDK для Go](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials).
Это включает указание учётных данных AWS с помощью переменных окружения или использование файла учётных данных.
AWS [именованные профили](https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html) поддерживаются `aws-iam-authenticator`
через переменную окружения `AWS_PROFILE`. Например, чтобы аутентифицироваться с учётными данными, указанными в профиле _dev_, `AWS_PROFILE` можно
экспортировать или указать явно (например, `AWS_PROFILE=dev kubectl get all`). Если `AWS_PROFILE` не задан, используется профиль _default_.
`AWS_PROFILE` также можно указать непосредственно в файле kubeconfig
[в рамках потока `exec`](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuration). Например, чтобы указать,
что `aws-iam-authenticator` всегда должен использовать учётные данные из именованного профиля _dev_, ваш kubeconfig будет содержать ключ `env`,
который задаёт профиль:
```yaml
apiVersion: v1
clusters:
- cluster:
server: ${server}
certificate-authority-data: ${cert}
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: aws
name: aws
current-context: aws
kind: Config
preferences: {}
users:
- name: aws
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws-iam-authenticator
env:
- name: "AWS_PROFILE"
value: "dev"
args:
- "token"
- "-i"
- "mycluster"
```
Этот метод позволяет неявно использовать подходящий профиль. Обратите внимание, что любые переменные окружения, заданные в рамках потока `exec`, будут иметь приоритет над тем, что уже установлено в вашем окружении.
#### Примечание для федеративных пользователей:
Федеративные пользователи AWS часто имеют «значащий» атрибут, сопоставленный с их предполагаемой ролью, например адрес электронной почты, через конфигурацию AWS учётной записи.
Эти предполагаемые сессии имеют [несколько частей](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable), `role id`
и `caller-specified-role-name`. По умолчанию, когда федеративный пользователь использует опцию `--role` в `aws-iam-authenticator` для принятия новой роли,
`caller-specified-role-name` будет преобразован в случайный токен, а `role id` переносится в новую предполагаемую роль.
Использование `aws-iam-authenticator token ... --forward-session-name` сопоставит исходный атрибут `caller-specified-role-name` с новой предполагаемой сессией STS.
Это может быть полезно для быстрой попытки связать «кто выполнил действие X в кластере K8».
Обратите внимание, **это не следует считать окончательным** и требует перекрёстной проверки через `role id` (который остаётся неизменным) с журналами CloudTrail,
поскольку пользователь потенциально может изменить это на стороне клиента.
## Авторизация API извне кластера
Возможно выполнять запросы к API Kubernetes от клиента, находящегося вне кластера, будь то с использованием
чистого REST API Kubernetes или одного из языковых клиентов Kubernetes
(например, [Python](https://github.com/kubernetes-client/python)). Для этого необходимо создать bearer-токен, который
включается в запрос к API. Этот bearer-токен требует, чтобы вы добавили строку `k8s-aws-v1.` с
base64-кодированной строкой подписанного HTTP-запроса к Query API STS GetCallerIdentity. Затем он отправляется в
заголовке `Authorization` запроса. Однако следует отметить, что IAM Authenticator явно опускает
base64-заполнение, чтобы избежать любых символов `=`, тем самым гарантируя строку, безопасную для использования в URL. Ниже приведён пример на
Python того, как этот токен может быть сконструирован:
```python
import base64
import boto3
import re
from botocore.signers import RequestSigner
def get_bearer_token(cluster_id, region):
STS_TOKEN_EXPIRES_IN = 60
session = boto3.session.Session()
client = session.client('sts', region_name=region)
service_id = client.meta.service_model.service_id
signer = RequestSigner(
service_id,
region,
'sts',
'v4',
session.get_credentials(),
session.events
)
params = {
'method': 'GET',
'url': 'https://sts.{}.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15'.format(region),
'body': {},
'headers': {
'x-k8s-aws-id': cluster_id
},
'context': {}
}
signed_url = signer.generate_presigned_url(
params,
region_name=region,
expires_in=STS_TOKEN_EXPIRES_IN,
operation_name=''
)
base64_url = base64.urlsafe_b64encode(signed_url.encode('utf-8')).decode('utf-8')
# remove any base64 encoding padding:
return 'k8s-aws-v1.' + re.sub(r'=*', '', base64_url)
# If making a HTTP request you would create the authorization headers as follows:
headers = {'Authorization': 'Bearer ' + get_bearer_token('my_cluster', 'us-east-1')}
```
## Устранение неполадок
Если ваш клиент завершается с ошибкой вида `could not get token: AccessDenied [...]`, вы можете попробовать принять роль напрямую с помощью AWS CLI:
```sh
# AWS CLI version of `aws-iam-authenticator token -r arn:aws:iam::ACCOUNT:role/ROLE`:
$ aws sts assume-role --role-arn arn:aws:iam::ACCOUNT:role/ROLE --role-session-name test
```
Если это не сработало, есть несколько возможных проблем, которые стоит проверить:
- Убедитесь, что ваши базовые учётные данные AWS доступны в вашей оболочке (команда `aws sts get-caller-identity` может помочь в диагностике).
- Убедитесь, что целевая роль разрешает доступ вашей исходной учётной записи (в политике доверия роли).
- Убедитесь, что у вашего исходного субъекта (пользователя/роли/группы) есть политика IAM, разрешающая `sts:AssumeRole` для целевой роли.
---
[Read more](https://github.com/kubernetes-sigs/aws-iam-authenticator)