一种使用 AWS IAM 凭据对 Kubernetes 集群进行身份验证的工具。 该工具的初始工作由 Heptio 推动。项目接收来自多位社区工程师的贡献,目前由 Heptio 和 Amazon EKS OSS 工程师维护。
如果你是运行在 AWS 上的 Kubernetes 集群的管理员,你本来就需要管理 AWS IAM 凭据来配置和更新集群。 通过使用 AWS IAM Authenticator for Kubernetes,你可以避免为 Kubernetes 访问单独管理一套凭据。 AWS IAM 还提供了许多不错的特性,例如带外审计跟踪(通过 CloudTrail)以及 2FA/MFA 强制。
如果你正在 AWS 上构建 Kubernetes 安装程序,AWS IAM Authenticator for Kubernetes 可以简化你的引导过程。
你无需费心将初始管理员凭据从新安装的集群中安全地带出来。
相反,你可以在集群配置阶段创建一个专用的 KubernetesAdmin 角色,并设置 Authenticator 以允许集群管理员登录。
假设你有一个在 AWS 上运行的集群,并且想为其添加 AWS IAM Authenticator for Kubernetes 支持,你需要:
首先,你必须创建一个或多个 IAM 角色,这些角色将映射到 Kubernetes 集群内的用户/组。 最简单的方法是登录 AWS 控制台:
这将创建一个没有任何权限的 IAM 角色,该角色可由你账户中的授权用户/角色代入。 记下你的角色的 Amazon Resource Name (ARN),下面你会用到它。
你也可以使用 AWS CLI 而非 AWS 控制台一步完成此操作:```sh
ACCOUNT_ID=$(aws sts get-caller-identity --output text --query 'Account')
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":{}}]}')
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. 运行服务器
该服务器旨在以 DaemonSet 的形式在您的每个主节点上运行,并使用主机网络,以便它可以暴露一个 localhost 端口。
有关示例 ConfigMap 和 DaemonSet 配置,请参阅 [`deploy/example.yaml`](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/HEAD/deploy/example.yaml)。
在应用之前,请为您的集群更新以下值:
- 替换 `config.yaml` 中的占位 IAM ARN(`arn:aws:iam::000000000000:...`)。
- 将 `clusterID` 设置为您的集群的唯一值。
- 验证 DaemonSet 的调度规则是否与您的控制平面节点标签/污点匹配。
然后部署它:```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
一旦 Pod 在控制平面节点上运行,aws-iam-authenticator server 将在宿主机上创建 webhook kubeconfig,路径为 /etc/kubernetes/aws-iam-authenticator/kubeconfig.yaml(或通过 --generate-kubeconfig 配置的路径)。
如果你正在构建自动化安装程序,还可以使用 aws-iam-authenticator init 轻松预生成证书、密钥和 webhook kubeconfig 文件。
该命令将生成文件并将其放置到配置的输出目录中。
你可以在每个主节点上启动 API 服务器之前运行此命令。 你也可以在配置主节点之前生成这些文件,并将它们安装到相应的宿主机路径中。
如果未预生成文件,aws-iam-authenticator server 将按需生成它们。
这也可以工作,但需要在安装后重启你的 Kubernetes API 服务器。
Kubernetes API 通过 令牌认证 webhook 与 AWS IAM Authenticator for Kubernetes 集成。
当你运行 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/` 已挂载到你的 API 服务器 Pod 中。
你可能还需要重启主节点上的 kubelet 守护进程,以加载更新后的静态 Pod 定义:```
systemctl restart kubelet.service
服务器的默认行为是仅从其配置文件的 mapUsers 和 mapRoles 字段获取映射。详见下文完整配置格式。
使用 --backend-mode 标志,你可以将服务器配置为从另外两个后端获取映射:EKS 风格的 ConfigMap(--backend-mode=EKSConfigMap)或 IAMIdentityMapping 自定义资源(--backend-mode=CRD)。默认后端是由服务器 Pod 挂载的服务器配置文件,对应 --backend-mode=MountedFile。
你可以传递这些后端的逗号分隔列表,让服务器按顺序搜索。例如,使用 --backend-mode=EKSConfigMap,MountedFile 时,服务器会先在 EKS 风格的 ConfigMap 中查找映射,如果找不到给定 IAM 角色/用户的映射,再查找服务器配置文件。如果同一 IAM 角色/用户的映射存在于多个后端,服务器将使用逗号分隔列表中靠前出现的后端的映射。在此示例中,如果在 EKS ConfigMap 中找到映射,那么无论服务器配置文件中是否存在重复或冲突的映射,都将使用该映射。
请注意,当设置单个后端时,服务器将仅从该后端获取映射,即使其他后端存在也会忽略。例如,使用 --backend-mode=CRD 时,服务器将仅从 IAMIdentityMappings 获取映射,并忽略挂载的文件和 EKS ConfigMap。
MountedFile这是映射的默认后端,对大多数用户来说已经足够。详见下文完整配置格式。
CRD (alpha)该后端将每个 IAM 映射建模为一个 IAMIdentityMapping Kubernetes 自定义资源。这种方法使你能够以 Kubernetes 原生的方式通过 kubectl 或 API 维护映射。此外,语法错误(如 YAML 缩进错位)更容易被发现,并且不会影响所有映射。
要设置 IAMIdentityMapping CRD,你首先需要 apply CRD 清单:```
kubectl apply -f deploy/iamidentitymapping.yaml
部署 CRD 后,你就可以创建对你的 IAM 身份进行建模的自定义资源,
请参阅
[`./deploy/example-iamidentitymapping.yaml`](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/HEAD/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
EKSConfigMapEKS 风格的 kube-system/aws-auth ConfigMap 作为后端。该 ConfigMap 的格式需与 EKS 集群中的完全一致:
https://docs.aws.amazon.com/eks/latest/userguide/add-user-role.html。如果你正在从 EKS 迁移或迁移到 EKS,并希望保留这些映射,或者除了其他 AWS 集群之外还运行 EKS,并希望在每个集群中拥有相同的映射,那么这会很有用。
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 可在启用 DynamicFile 模式的 kind 集群上进行体验。
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 了解如何配置保留前缀。
最后,服务器设置完成后,你需要进行认证。
你仍然需要一个 kubeconfig,其中包含集群的公开数据(集群 CA 证书、端点地址)。
但是,你的配置中的 users 部分应包含一个 exec 部分(请参阅 kubectl 凭据插件文档):```yaml
users:
这意味着 `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 将使用你的 kubeconfig 中提供的参数 `exec` `aws-iam-authenticator` 二进制文件,该二进制文件将生成一个令牌并将其传递给 apiserver。
该令牌有效期为 15 分钟(AWS 允许的最短时间),可以多次重用。
你还可以在生成令牌时通过包含 `--session-name or -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)。
## 它是如何工作的?
它使用 AWS [`sts:GetCallerIdentity`](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html) API 端点来工作。
该端点会返回有关你用来连接它的任意 AWS IAM 凭据的信息。
#### 客户端 (`aws-iam-authenticator token`)
我们以一种有点不寻常的方式使用此 API:让 Authenticator 客户端生成并预签名对该端点的请求。
我们将该请求序列化为一个令牌,该令牌可以通过 Kubernetes 身份验证系统。
#### 服务端 (`aws-iam-authenticator server`)
该令牌通过 Kubernetes API 服务器传递,并经由 webhook 配置进入 Authenticator 服务器的 `/authenticate` 端点。
Authenticator 服务器会验证预签名请求的所有参数,以确保没有任何异常。
然后,它将请求提交到真实的 `https://sts.amazonaws.com` 服务器,该服务器会验证客户端的 HMAC 签名并返回有关用户的信息。
现在,服务器知道了客户端的 AWS 身份,它会通过简单的静态映射将此身份转换为 Kubernetes 用户和组。
这种机制借鉴自 [Vault](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method),并做了一些更改。
## 什么是集群 ID?
Authenticator 集群 ID 是每个集群唯一的标识符,可防止某些重放攻击。
具体来说,它可以防止一个 Authenticator 服务器(例如,在开发环境中)使用客户端的令牌来向另一个集群中的另一个 Authenticator 服务器进行身份验证。
集群 ID 确实需要每个集群唯一,但不需要保密。
一些好的选择是:
- 一个随机 ID,例如通过 `openssl rand 16 -hex` 生成
- 你的 Kubernetes API 服务器的域名
[Vault 文档](https://www.vaultproject.io/docs/auth/aws.html#iam-auth-method) 也解释了这个攻击 (参见 `X-Vault-AWS-IAM-Server-ID`)。
## 指定凭据及使用 AWS 配置文件
可以使用任何可用的方法为 `aws-iam-authenticator` 指定凭据,这些方法由
[AWS SDK for 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 配置实现。这些代入会话有几个组成部分,包括 role id 和 caller-specified-role-name。默认情况下,当联邦用户使用 aws-iam-authenticator 的 --role 选项代入新角色时,caller-specified-role-name 会被转换为随机令牌,而 role id 会延续到新代入的角色。
使用 aws-iam-authenticator token ... --forward-session-name 会将原始的 caller-specified-role-name 属性映射到新的 STS 代入会话。这有助于快速尝试关联“谁在 K8 集群上执行了操作 X”。
请注意,这不应被视为最终结果,并且需要通过 role id(保持一致)与 CloudTrail 日志进行交叉核对,因为用户可能可以在客户端更改此值。
可以从集群外部的客户端向 Kubernetes API 发起请求,无论是使用裸的 Kubernetes REST API,还是使用特定语言的 Kubernetes 客户端之一(例如 Python)。为此,您必须创建一个随请求一起发送到 API 的 bearer 令牌。此 bearer 令牌要求您将字符串 k8s-aws-v1. 与一个经过签名的 HTTP 请求的 base64 编码字符串拼接在一起,该请求发送到 STS GetCallerIdentity Query API。然后将其放入请求的 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)
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 凭证在 shell 中可用(aws sts get-caller-identity 有助于排查此问题)。
确保目标角色允许你的源账户访问(在角色信任策略中)。
确保你的源主体(用户/角色/组)拥有允许对目标角色执行 sts:AssumeRole 的 IAM 策略。
确保你没有在用户、组或 AWS Organizations 中附加任何显式拒绝策略,以免阻止 sts:AssumeRole。
尝试在 Policy Simulator 中模拟 sts:AssumeRole 调用。
客户端和服务器具有相同的配置格式。 它们可以共享完全相同的配置文件,因为配置中不存储任何机密信息。```yaml
clusterID: my-dev-cluster.example.com
aws-iam-authenticator tokendefaultRole: arn:aws:iam::000000000000:role/KubernetesAdmin
server:
port: 21362 # (default)
stateDir: /var/aws-iam-authenticator # (default)
path where a generated webhook kubeconfig will be stored.generateKubeconfig: /etc/kubernetes/aws-iam-authenticator.kubeconfig # (default)
ec2DescribeInstancesRoleARN: arn:aws:iam::000000000000:role/DescribeInstancesRole
scrubbedAccounts:
@ characters- characters.mapRoles:
mapUsers:
mapAccounts:
backendMode:
## 开发
参阅[开发](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/HEAD/docs/development.md)页面。
## 社区、讨论、贡献与支持
了解如何通过[社区页面](http://kubernetes.io/community/)与 Kubernetes 社区互动。
您可以通过以下方式联系此项目的维护者:
- [Slack](https://kubernetes.slack.com/messages/sig-aws)
- [邮件列表](https://groups.google.com/forum/#!forum/kubernetes-sig-aws)
### 行为准则
参与 Kubernetes 社区需遵守 [Kubernetes 行为准则](https://github.com/kubernetes-sigs/aws-iam-authenticator/blob/HEAD/code-of-conduct.md)。