亚马逊AWS官方博客

OpenSource | 控制对 AWS 云中运行的 Amazon EKS 集群的访问

我们的客户询问如何才能安全地访问他们的 Amazon Elastic Container Service for Kubernetes (Amazon EKS) 或 EC2 上的 Kubernetes 集群。我们的企业客户已经实施了 Active Directory (AD)、Active Directory 联合身份验证服务 (ADFS) 或轻量目录访问协议 (LDAP),以用于本地身份与访问管理,并在 AWS 上使用 AWS Identity and Access Management (IAM) 服务。许多客户都已在本地采用 Kubernetes,并且希望使用通用的基于角色的访问控制 (RBAC) 策略来控制本地和 AWS 云中对 Kubernetes 资源的访问权限。这促使了我们与 Heptio 的合作,该组织已经建立了庞大的社群项目系列,包括 Heptio Authenticator。Amazon EKS 开放源团队以 Heptio Authenticator 为起点,将 AWS IAM 与 Kubernetes RBAC 进行映射。AWS 和 Heptio 的工程师是项目的核心维护人员,与一群出色的社群工程师合作,将项目捐献给 Kubernetes 特别兴趣小组 AWS(又名 SIG-AWS)。当您使用 Amazon EKS、EC2 上的 Kubernetes 或本地 Kubernetes 时,您可以使用 Kubernetes RBAC 对象和角色约束机制,声明 AWS IAM 用户在 AWS 云中或 AD 用户在本地的操作权限。在声明之后,您可以将 AWS 托管的 IAM 用户角色或 AD 用户角色验证为共同的 Kubernetes RBAC 角色,并对您的 Kubernetes 集群启用端到端身份验证和授权。在此博文中,我们将向您介绍如何使用 AWS Single Sign-On (SSO)、AWS 管理的 Microsoft Active Directory 服务 以及 AWS IAM 身份验证器来控制对 AWS 云中运行的 Amazon EKS 集群的访问。这同样适用于使用 kops 在 AWS 上创建的自我管理的 Kubernetes 集群。我们选择利用 AWS 托管服务来模拟您可能在本地使用的第三方身份与访问管理工具,然后使用 AWS Identity and Access Management (IAM) 的联合访问权限。为了实施此方法,您将使用如下服务:

  • AWS Organizations 实现从单个 AWS 主账户来管理托管账户内部的 IAM 角色和策略。
  • AWS Single Sign-On 通过 AWS Directory Service 与 Microsoft Active Directory 集成,允许用户使用一组临时的 AWS 凭证来访问 AWS 命令行界面
  • AWS 管理的 Microsoft AD 提供完全托管的 Microsoft Active Directory,从而方便管理您的所有用户和凭证。此组件可以利用连接器和/或联合身份验证,用您自己的 AD 实施更换。
  • AWS Identity and Access Management (IAM) :为 AWS 客户/用户提供 AWS 云的原生身份与访问管理工具。
  • AWS IAM Authenticator for Kubernetes 用于将 AWS IAM 用户凭证与 Kubernetes 身份进行映射工具,因此熟悉 AWS IAM 的用户不需要维护单独的 Kubernetes 凭证集。

有关其他非托管型联合访问管理解决方案以及支持 SAML 2.0 的身份提供商的详细描述,请参阅启用对 AWS 的 Windows Active Directory、ADFS 和 SAML 2.0 联合身份验证以及如何实施适用于使用 SAML 2.0 的联合 API/CLI 访问的通用解决方案

先决条件

在您开始使用前,请确保满足如下条件:

  1. 您拥有两个 AWS 账户,即账户 A(主账户)和账户 B(成员账户)。
  2. 您已经在账户 A(主账户)中根据 AWS SSO 先决条件的要求设置了 AWS Organizations 服务
  3. 您已经将账户 B(成员账户)添加到在账户 A(主账户)中创建的组织
  4. 您已经设置了账户 A(主账户)中的 AWS 管理的 Microsoft AD 在 us-east-1 区域的链接。
  5. 您已经部署了一个 Windows EC2 实例来管理 AWS Microsoft AD 并将它加入到 AD 域。确保您已经安装了 AD DS 和 AD LDS 工具
  6. 您已经从 AWS 管理控制台启用了 AWS SSO
  7. 您已经将 AWS SSO 连接到 Microsoft AD
  8. 您已经在任何可用区域在账户 B(成员账户)中部署了 Amazon EKS 集群。
  9. 可选:您必须将 AWS SSO 中的属性映射到您连接的目录

注意: 如果您使用本地 AD,您需要执行一个额外的步骤才能建立上文第 7 步所述对 AWS 账户的 SSO 访问。对于该步骤,您可以:

  • 在 AWS 管理的 Microsoft AD(在上文第 4 步创建)和本地 AD 之间建立双向信任关系。

或者

  • 在 AWS 中创建 AD Connector 以将请求重定向至本地 AD。

汇集完成

SAML 2.0 — 与 AD 和 SSO 集成 — 示意图

在下面的几个部分,我们会通过 AWS SSO AssumedRoles 将 AD 组映射到 AWS IAM 角色。然后使用 Kubernetes configMaps 和角色,将关联的 IAM 角色映射到 Kubernetes RBAC 角色。这将利用开放源 AWS IAM Authenticator 来通过来自 kubectl 的 IAM 身份完成。出于演示目的,我们将为 AWS-EKS-Admins 组的用户提供对 EKS 集群的完全权限(类似于 Kubernetes 中赋予默认集群管理员角色的权限),并且我们将为 AWS-EKS-Dev 组的用户提供对某些 Kubernetes 资源的只读访问权限。映射汇总表如下:

Microsoft AD 组 AWS IAM 角色权限 Kubernetes RBAC 角色 Kubernetes RBAC 角色权限
AWS-EKS-Admins { “Effect”: “Allow”, “Action”: “sts:AssumeRole”, “Resource”: “*” } ad-cluster-admins – apiGroups:[‘*’] resources:[‘*’] verbs: [‘*’]
AWS-EKS-Dev { “Effect”: “Allow”, “Action”: “sts:AssumeRole”, “Resource”: “*” } ad-cluster-devs – apiGroups: [“”] resources: [“services”, “endpoints”, “pods”, “deployments”, “ingress”] verbs: [“get”, “list”, “watch”]

有关 RBAC 在 Kubernetes 中的运行机制,请参阅 Kubernetes 参考文档

1. 创建 Microsoft AD 中的用户/组

我们将在 Microsoft AD 中创建两个 AD 组(AWS-EKS-Prod 和 AWS-EKS-Dev)。此外,我们还将创建一个 devuser 和一个 adminuser,并将分别将这两个用户添加到 AWS-EKS-Admins 组和 AWS-EKS-Dev 组。从已经加入 AD 域的 Windows EC2 实例执行如下操作:

  • 导航至 Active Directory 用户和计算机 mmc 控制台。您也可使用下文参考所示的 powershell。
  • 在 AD 域中创建 AWS-EKS-Admins 组。
PS C:\Users\Admin> New-ADGroup -Name "AWS-EKS-Admins" -SamAccountName AWS-EKS-Admins -GroupCategory Security -GroupScope Global -DisplayName "AWS-EKS-Admins" -Path "OU=test,DC=test,DC=eks,DC=Com" -Description "Members of this group are AWS EKS Administrators"
  • 在 AD 域中创建 AWS-EKS-Dev 组。
PS C:\Users\Admin> New-ADGroup -Name "AWS-EKS-Dev" -SamAccountName AWS-EKS-Dev -GroupCategory Security -GroupScope Global -DisplayName "AWS-EKS-Dev" -Path "OU=test,DC=test,DC=eks,DC=Com" -Description "Members of this group are AWS EKS Developers"
  • 创建 adminuser
PS C:\Users\Admin> $password = "EKSRulz!" | ConvertTo-SecureString -AsPlainText -Force
PS C:\Users\Admin> New-ADUser -Name adminuser -GivenName adminuser -Surname adminuser -UserPrincipalName adminuser@test.eks.com -Path "OU=Users,OU=test,DC=test,DC=eks,DC=Com" -AccountPassword $Password -ChangePasswordAtLogon $True -Enabled $True
  • 创建 devuser
PS C:\Users\Admin> $password = "EKSRulz!"| ConvertTo-SecureString -AsPlainText -Force
PS C:\Users\Admin> New-ADUser -Name devuser -GivenName devuser -Surname devuser -UserPrincipalName devuser@test.eks.com -Path "OU=Users,OU=test,DC=test,DC=eks,DC=Com" -AccountPassword $Password -ChangePasswordAtLogon $True -Enabled $True
  • adminuser 添加到 AWS-EKS-Admins 组
PS C:\Users\Admin> Add-ADGroupMember -Identity AWS-EKS-Admins -Members adminuser
  • devuser 添加到 AWS-EKS-Dev 组
PS C:\Users\Admin> Add-ADGroupMember -Identity AWS-EKS-Dev -Members devuser

2. 将 AD 组分配给 AWS SSO

现在我们已经创建了 AD 用户/组,我们将分配组(以及相应的用户)对 AWS 账户 B(EKS 集群所在的账户)的访问权限。此外,我们还将添加一条权限设置,允许账户 A(主账户)扮演账户 B(成员账户)中的角色,从而访问该账户中的资源。请注意在此阶段,并未向 AD 用户/组分配扮演角色的具体权限。在默认情况下,扮演角色不会拥有执行任何操作的权限。具体的权限将通过下一部分的 Kubernetes RBAC 定义。在账户 A(主账户)中导航至 AWS SSO 控制台并执行如下操作:

  • 在左侧窗格中选择 AWS 账户 选项卡,然后选择 AWS 账户 A 以分配用户。单击 Assign Users(分配用户)
  • 搜索 AD 组 AWS-EKS-DevAWS-EKS-Admins 。单击 Next: Permission sets(下一步:权限设置)

AWS 账户分配用户

  • 选择 Create new permission set(创建新权限设置) ,然后再下一页选择 Create a custom permission set(创建自定义权限设置) 。提供权限设置的名称,例如“AD-EKS-Dev-AssumedRole”,然后选中 Create a custom permissions policy(创建自定义权限策略) 复选框。将下列权限策略复制到窗口中,然后单击 创建 。以下策略将允许账户 A(主账户)中 IAM 用户扮演信任该用户账户的任何账户中的任何角色。在响应 AssumeRole API 调用时,AWS STS 将返回一组临时安全凭证以访问 AWS 资源。
{
    "Version": "2012-10-17",
    "Statement": [
        {
          "Effect": "Allow",
          "Action": "sts:AssumeRole",
          "Resource": "*"
        }
    ]
 }
  • 选中 AD-EKS-Dev-AssumeRole 复选框,然后单击 完成
  • AWS-EKS-Admins 重复前面的流程,为该组分配类似的权限。

在背后,AWS SSO 会在账户 B(成员账户)中执行如下操作:

  • 在 AWS IAM 中配置一个身份提供商 (IdP),从而建立 SAML 联合身份验证。身份提供商使得 AWS 账户信任 AWS SSO,从而允许 SSO 访问。
  • 创建一个 AWS IAM 角色并将上述权限设置作为策略附加到角色。这是 AWS SSO 代表 Microsoft AD 用户/组扮演的角色,用于访问 AWS 资源。

3. 通过 Kubernetes RBAC 配置角色权限

这时,我们已经设置了 Microsoft AD 来控制 AWS SSO 用户门户的身份验证。 此外,我们还通过指定向账户 B(EKS 集群所在的账户)赋予访问权限的 AD 组,设置了部分授权。但尚未明确访问控制(即授予 AD 用户的权限级别)。在这一部分,我们将演示如何通过 AWS IAM 角色实施联合身份验证,配置 Kubernetes RBAC 以定义对 AD 用户/组的访问控制。在执行如下步骤前,请确保满足如下条件:

  1. 您拥有正在运行的 Kubernetes 集群,拥有工作线程节点。
  2. 您已经通过集群管理员(创建者)配置了 kubeconfig 来管理集群。

注意:如果您使用 Amazon EKS,有关配置 Amazon EKS 集群的详细步骤请参阅 Amazon EKS 入门 创建演示命名空间 首先让我们创建一个名为 demo-service 的演示命名空间。我们将使用此命名空间来演示通过 Kubernetes RBAC 执行 AWS-EKS-Admins 和 AWS-EKS-Dev AD 组的完全访问权限和只读访问权限控制。

$ kubectl create namespace demo-service

然后,让我们为 AWS-EKS-Dev 和 AWS-EKS-Admins 组创建关联的 Kubernetes 角色,每组一个。创建集群角色

$ cat role.yaml
# role.yaml
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   name: demo-service:ad-cluster-admins
   namespace: demo-service
 rules:
 - apiGroups: ["*"]
   resources: ["*"]
   verbs: ["*"]
 ---
 apiVersion: rbac.authorization.k8s.io/v1
 kind: Role
 metadata:
   name: demo-service:ad-cluster-devs
   namespace: demo-service
 rules:
 - apiGroups: [""]
   resources: ["services", "endpoints", "pods", "deployments", "ingress"]
   verbs: ["get", "list", "watch"]

然后,我们会将这些角色应用到集群以启用角色。

$ kubectl apply -f role.yaml

修改身份验证器配置图 现在让我们修改身份验证器配置,以允许 EKS 访问这些组。您将需要取得 IAM 分别为 AWS-EKS-Dev 和 AWS-EKS-Admins 这两个 AD 组扮演的角色的角色 arns。您可以使用下面的命令执行该操作:

$ aws iam list-roles | grep Arn | grep AD-EKS-

然后您需要编辑 aws-auth ConfigMap:

$ kubectl edit configmap aws-auth --namespace kube-system

此命令将在您的编辑器中打开文件。然后我们可以将下列项目添加到 mapRoles 部分。请确保满足下列条件:

  1. 对于 rolearn,请务必删除 rolearn url 中的 /aws-reserved/sso.amazonaws.com/,否则该 arn 将无法授权为有效的用户。
  2. 请确保组与您在下文的角色约束中指定的组参数匹配。
# ... mapRoles config
 - rolearn: arn:aws:iam::141548511100:role/AWSReservedSSO_AWS-EKS-Admins_b7e6a177cfc720e6
   username: adminuser:{{SessionName}}
   groups:
   - demo-service:ad-cluster-admins
 - rolearn: arn:aws:iam::141548511100:role/AWSReservedSSO_AWS-EKS-Dev-AssumedRole_7f87046f4b89cf97
   username: devuser:{{SessionName}}
   groups:
 - demo-service:ad-cluster-devs

一旦您完成添加,请保存并关闭文件。 创建角色约束 最后,我们可以将这些角色约束到 Kubernetes 中应当拥有 demo-service 命名空间访问权限的相关组。AWS-EKS-Admin 角色将拥有 demo-service 命名空间的完全访问权限,AWS-EKS-Dev 角色则拥有只读访问权限。在如下的命令中,我们会创建 operations-team-binding 和 development-team-binding 这两个角色约束,该角色约束会将角色 demo-service:ad-cluster-admin 和角色 demo-service:ad-cluster-devs 分配给 demo-service 命名空间中的 Kubernetes 组 demo-service:ad-cluster-admins 和 demo-service:ad-cluster-devs。demo-service:ad-cluster-admins 的角色约束:

$ kubectl create rolebinding operations-team-binding --role demo-service:ad-cluster-admins --group demo-service:ad-cluster-admins --namespace demo-service

demo-service:ad-cluster-devs 的角色约束:

$ kubectl create rolebinding development-team-binding --role demo-service:ad-cluster-devs --group demo-service:ad-cluster-devs --namespace demo-service

修改 kubeconfig 现在我们可以为每组角色约束创建新的 KUBECONFIG 文件,一个用于开发用户,另一个用于管理员用户。复制您 kubeconfig 文件,然后修改 eks 集群的用户部分,与以下类似。~/.kube/config-test-eks-cluster-1-dev

- name: test-eks-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      command: heptio-authenticator-aws
      args:
      - "token"
      - "-i"
      - "test-eks-cluster"
      - "-r"
      - "<RoleArn of AWS-EKS-Dev AssumedRole>"

~/.kube/config-test-eks-cluster-1-admins

- name: test-eks-cluster
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      command: heptio-authenticator-aws
      args:
      - "token"
      - "-i"
      - "test-eks-cluster"
      - "-r"
      - "<RoleArn of AWS-EKS-Admins AssumedRole>"

注意: 对于上文的 -r 参数,请指定此情况下的完整 rolearn,包括 rolearn 中的路径。例如:

arn:aws:iam::1234567890:role/ aws-reserved/sso.amazonaws.com/ AWSReservedSSO_AWS-EKS-Admins

测试一切工作正常

下面让我们尝试向 apiserver 发送请求,以验证端到端的身份验证和授权正常工作。如要作为 AD 用户验证身份,请从 AWS SSO 门户取得该用户的环境变量。访问门户网站的 URL,如下所示:

欢迎使用 AWS Single Sign-On 页面

下一步:

  1. 使用有效的 AD 用户登录 AWS SSO 用户门户,例如 adminuser,该用户是 Microsoft AD AWS-EKS-Admins 组的成员。
  2. 单击 命令行或编程访问 链接,以检索该用户的环境变量。
  3. 将环境变量导出到终端。

此外,请确保在运行如下测试时设置了相关的 kubeconfig 上下文:adminuser 示例:

$ kubectl run snowflake --image=kubernetes/serve_hostname --replicas=2 --namespace=demo-service
deployment.apps "snowflake" created

$  kubectl get pods --namespace=demo-service

NAME                         READY      STATUS    RESTARTS  AGE
snowflake-54fccfcd67-9k8dq   0/1        Pending   0         3m
snowflake-54fccfcd67-qq59k   0/1        Pending   0         3m

$ kubectl get pods
Error from server (Forbidden): pods is forbidden: User "adminuser-1529910544824263459" cannot list pods in the namespace "default"

devuser 示例:

$ kubectl run snowflake --image=kubernetes/serve_hostname --replicas=2 --namespace=demo-service
Error from server (Forbidden): deployments.extensions is forbidden: User "devuser-1529910185702205240" cannot create deployments.extensions in the namespace "demo-service"

$ kubectl get pods --namespace=demo-service
NAME                         READY     STATUS       RESTARTS  AGE
snowflake-54fccfcd67-9k8dq   0/1       Pending      0         1m
snowflake-54fccfcd67-qq59k   0/1       Pending      0         1m

$ kubectl get pods
Error from server (Forbidden): pods is forbidden: User "devuser-1529910584505925203" cannot list pods in the namespace "default"

与预期一样,adminuser 拥有 demo-service 命名空间的完全权限,但不拥有其他命名空间的访问权限。而 devuser 拥有 demo-service 命名空间的只读访问权限。

小结

在此博文中,我们演示了 AWS Microsoft Active Directory 中的身份如何通过 AWS SSO 扮演 AWS IAM 角色,以使用 AWS CLI 进行身份验证。然后,AWS IAM 角色可以通过 K8s configMap、集群角色和角色约束映射到 Kubernetes RBAC,以向活动目录用户授予对 kubernetes 命名空间的访问权限。有关项目的更多信息请参阅:AWS-IAM-Authenticator,欢迎您提出反馈意见和作出贡献。