亚马逊AWS官方博客

使用 Dex 和 dex-k8s-authenticator 对 Amazon EKS 进行身份验证

我们在与客户沟通过程中了解到,一些从基于EC2自建的Kubernetes迁移到使用Amazon Elastic Kubernetes Service (Amazon EKS) 托管服务的客户,在使用过程中体会到了Amazon EKS带来的高性能、高可靠、自动扩展等等优势,但也有遇到一些使用不便的情况。这是由于客户在基于EC2自建Kuberntes的环境中,可以完全掌控包括Api Server的启动配置在内的所有资源,而托管的EKS不支持客户手动管理Api Server。这给客户带了一些困扰,比如之前通过使用Kubernetes API Server 功能结合外部OIDC Provider进行用户统一管理的客户,在EKS上无法像之前那样使用。虽然有一些变通的方法,如:使用kube-oidc-proxy 实现,但是配置和管理复杂度增加了很多。

Amazon EKS 近期上线了新功能,在EKS 1.16后的版本支持配置OIDC Provider,简化了用户管理配置。为了方便大家熟悉和使用该功能,本文将通过一步步的配置,介绍如何使用Dex和dex-k8s-authenticator结合新功能来实现EKS对外部用户进行身份验证。本方案不仅支持对多个Amazon EKS集群进行统一认证管理,同时也可以支持将其他云厂商托管的Kubernetes通过Dex进行统一身份认证。本文中,我们将展示两部分内容:一、对 Amazon EKS 进行外部身份认证后执行 kubectl 命令。 二、对 Amazon EKS 进行外部身份认证后浏览 Kubernetes Dashaborad。

 

第一部分:

核心认证流程如下图:

 

方案中的主要组件说明:

  1. Dex 是一种身份认证服务,它使用 OpenID Connect 来驱动其他应用程序的身份验证。Dex 通过“connectors”充当其他身份提供商的门户。 这让 dex 将身份验证推到 LDAP 服务器、SAML 提供商或已建立的身份提供商(如 GitHub、Gitlab、Google 和 Active Directory等)。 客户端编写身份验证逻辑以与 dex 交互认证,然后 dex 通过 connector 转发到后端用户认证方认证,并返回给客户端Oauth2 Token。与其相似的还有 Keycloak,auth0 等。
  2. dex-k8s-authenticator 是一个web-app,它可以与 Dex 进行交互并获取 Dex 生成的 token 创建和修改 kubeconfig 文件的命令。用户执行这些生成的命令后可以完成 kubeconfig 文件配置。

 

前置条件:

  1. 准备EKS集群,版本大于16。 EKS 1.16 或以上的版本支持 OIDC Provider
  2. 本文中将使用 github 来模拟用户身份提供验证方,需要准备 github 账户并启用 team 功能
  3. 需要有一个公网域名。 Amazon EKS 要求OIDC 身份提供商的颁发者 URL 必须可公开访问,以便 Amazon EKS 能够发现签名密钥。Amazon EKS 不支持拥有自签名证书的 OIDC 身份提供商。
  4. (可选)建议打开 Amazon EKS 打开控制平面 CloudWatch 日志,通过查看 CloudWatch log 方便排查配置错误。开启步骤,请参阅 启用和禁用控制平面日志设置开启。

 

部署测试:

步骤一、安装 Nginx ingress controller

在创建Nginx ingress controller前,先检查确认EKS集群公有子网的标签(Tags),确认添加以下标签。

kubernetes.io/cluster/<EKS_CLUSTER_NAME>=shared

本文中NGINX ingress controller 用来将流量路由到 Dex 和 dex-k8s-authenticator , 安装命令如下

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.45.0/deploy/static/provider/aws/deploy.yaml

安装完成后会自动创建一个 internet-facing 的NLB。执行以下命令确认安装完成,

kubectl get svc -n ingress-nginx

步骤二、安装cert-manager

cert-manager 用于从 Let’s Encrypt 获取 TLS 证书。 这些证书将分配给 Dex 和 dex-k8s-authenticator 的 ingress。 安装 cert-

manager 命令:

添加 JetStack Helm 仓库:

helm repo add jetstack https://charts.jetstack.io

更新 Helm cache:

helm repo update

安装 chart:

helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.3.1 --set installCRDs=true

在 Amazon EKS 中创建证书签发机构

cat << 'EOF' | kubectl apply -f -
kind: ClusterIssuer
apiVersion: cert-manager.io/v1
metadata:
  name: acme
spec:
  acme:
    email: alias@yourdomain.com
    preferredChain: ''
    privateKeySecretRef:
      name: acme-account-key
    server: 'https://acme-v02.api.letsencrypt.org/directory'
    solvers:
      - http01:
          ingress:
            class: nginx
EOF

步骤三、配置 github OAuth App

登陆 github 账户,在 “setting” 中选择 “Organizations” 选项:

使用免费的账户就可以满足本文需求,创建 Organization 后,在 “Setting” -> “Developer setting” 选项卡中新建一个 OAuth App:

Homepage URL 部分填入准备为 Dex 使用的 URL,例如:https://dex.yourdomain.com

Authorization callback URL 部分填入 Homepage URL 加 /callback,例如:https://dex.yourdomain.com/callback

创建完成后记录下 Client ID 和 Client Secret ,后续配置 Dex 使用。

步骤四、安装和配置Dex

添加 Dex Helm 仓库

helm repo add dex https://charts.dexidp.io

Update Helm cache

helm repo update

为 Dex Helm 创建 Value File,使用您自己的域名和上述步骤记录的信息替换对应内容

cat << 'EOF' > dex.yaml
ingress:
  enabled: true
  className: nginx
  annotations:
    kubernetes.io/tls-acme: "true"
    cert-manager.io/cluster-issuer: acme
  hosts:
    - host: dex.yourdomain.com
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls:
    - secretName: dex-tls
      hosts:
        - dex.yourdomain.com

config:
  issuer: https://dex.yourdomain.com

  storage:
    type: kubernetes
    config:
      inCluster: true

  oauth2:
    responseTypes: ["code", "token", "id_token"]
    skipApprovalScreen: true

  connectors:
    - type: github
      id: github
      name: GitHub
      config:
        clientID: "{{ .Env.GITHUB_CLIENT_ID }}"
        clientSecret: "{{ .Env.GITHUB_CLIENT_SECRET }}"
        redirectURI: https://dex.yourdomain.com/callback
        orgs:
          - name: your-github-org-name
            teams:
              - your-github-team-name

  staticClients:
    - id: your-cluster-client-id
      secret: your-cluster-client-secret
      name: "Your EKS Cluster"
      redirectURIs:
        - https://login.yourdomain.com/callback
# Note: this will inject the environment variables directly to the pods.# In a production environment you should mount these keys from a secret using envFrom.# See https://artifacthub.io/packages/helm/dex/dex#values
env:
  GITHUB_CLIENT_ID: "your-github-client-id"
  GITHUB_CLIENT_SECRET: "your-github-client-secret"
EOF

安装 Dex chart

helm install dex dex/dex --namespace dex --create-namespace --version 0.2.0 --values dex.yaml

步骤五、安装和配置dex-k8s-authenticator

添加 如下 Helm 仓库

helm repo add skm https://charts.sagikazarmark.dev

Update Helm cache

helm repo update

获取 Amazon EKS 集群客户端证书:

aws eks describe-cluster --name <cluster-name> --query 'cluster.certificateAuthority' --region <region> --output text | base64 -d

为 dex-k8s-authenticator 创建 Value 文件:

cat << 'EOF' > dex-k8s-authenticator.yaml 
config:
  clusters:
    - name: your-cluster
      short_description: "Your cluster"
      description: "Your EKS cluster"
      issuer: https://dex.yourdomain.com
      client_id: your-cluster-client-id
      client_secret: your-cluster-client-secret
      redirect_uri: https://login.yourdomain.com/callback
      k8s_master_uri: https://your-eks-cluster-endpoint-url
      k8s_ca_pem: |
        -----BEGIN CERTIFICATE-----
        YOUR CLIENT CERTIFICATE DATA
        -----END CERTIFICATE-----
  
ingress:
  enabled: true
  className: nginx
  annotations:
    kubernetes.io/tls-acme: "true"
    cert-manager.io/cluster-issuer: acme
  hosts:
    - host: login.yourdomain.com
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls:
    - secretName: dex-k8s-authenticator-tls
      hosts:
        - login.yourdomain.com
EOF

安装 dex-k8s-authenticator chart

helm install dex-k8s-authenticator skm/dex-k8s-authenticator --namespace dex --version 0.0.1 --values dex-k8s-authenticator.yaml

步骤六、配置Amazon EKS OIDC Provider

参考 官方文档步骤 为 Amazon EKS 关联OIDC提供商,需要注意:

Client ID 输入上文创建 Dex 时设置的 staticClients 对应的 id 字段内容。

Username  输入 email

Groups 输入 groups

步骤七、在EKS中创建ClusterRole和ClusterRoleBinding

本文测试创建一个只读权限的 cluster role,您可以根据自己的实际需求创建分配对应的权限。

cat << 'EOF' | kubectl apply -f - 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-read-all
rules:
- apiGroups:
    - ""
    - apps
    - autoscaling
    - batch
    - extensions
    - policy
    - rbac.authorization.k8s.io
    - storage.k8s.io
  resources:
    - componentstatuses
    - configmaps
    - cronjobs
    - daemonsets
    - deployments
    - events
    - endpoints
    - horizontalpodautoscalers
    - ingress
    - ingresses
    - jobs
    - limitranges
    - namespaces
    - nodes
    - pods
    - pods/log
    - pods/exec
    - persistentvolumes
    - persistentvolumeclaims
    - resourcequotas
    - replicasets
    - replicationcontrollers
    - serviceaccounts
    - services
    - statefulsets
    - storageclasses
    - clusterroles
    - roles
  verbs:
    - get
    - watch
    - list
- nonResourceURLs: ["*"]
  verbs:
    - get
    - watch
    - list
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create"]
EOF

创建 ClusterRoleBinding:

cat << 'EOF' | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dex-cluster-auth
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-read-all
subjects:
  - kind: Group
    name: "your-github-org:your-github-team"
    apiGroup: rbac.authorization.k8s.io
EOF
Bash

步骤八、配置域名解析

在您的 DNS 服务商(AWS Route53 或其他域名 DNS 服务商)处配置域名解析。增加以下两个域名解析信息。 CNAME 到 步骤一中创建的 NLB 地址。

步骤九、登陆测试

输入 https://login.yourdomain.com   登陆 github 账号并给 dex-auth 授权

登陆并授权后自动跳转到 dex-k8s-authenticator 页面,dex-k8s-authenticator 生成配置 kubeconfig 文件的命令:

执行上述命令完成 kubeconfig 配置后,登陆 Amazon EKS 进行测试:

可以看到通过 OIDC 用户可以登陆Amazon EKS,并且用户权限符合预期。

 

第二部分:

在这部分中,我们演示如何在 Amazon EKS 中将 Kubernetes Dashboard 设置对外访问并使用上一部分生成的 Token 登陆。

步骤一、安装 Kubernetes Dashboard

参考 部署 Kubernetes 控制面板 (Web UI)  ,安装 Dashboard。安装完成后使用 kubectl proxy 模式访问确认安装成功。

步骤二、配置 Kubernetes Dashboard Ingress

配置 Ingress 以允许从外部直接访问 Kubernetes Dashboard。将以下内容保存为 dashboard-ingress.yaml 并执行。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    kubernetes.io/tls-acme: "true"
    cert-manager.io/cluster-issuer: acme
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
  name: external-auth-oauth2
  namespace: kubernetes-dashboard
spec:
  rules:
  - host: <dashboard.yourdomain.com>
    http:
      paths:
      - backend:
          serviceName: kubernetes-dashboard
          servicePort: 443
        path: /
  tls:
  - hosts:
    - <dashboard.yourdomain.com>
    secretName: dashboard-secret

这里要注意 Amazon EKS 暴露 443 端口,需通过 https 协议访问,要在 annotations 单独设置。

kubectl apply -f dashboard-ingress.yaml

步骤三、登陆测试

浏览器访问步骤二中设置的域名

输入第一部分生成的 Token 后完成认证,如下图所示,复制红色线框内的 Token 内容。


登陆到 Kubernetes Dashboard 中的用户也只有第一部分中定义的只读权限。

至此,完成两部分配置内容。

 

总结:

在这篇文章中,我们介绍了如何使用 Amazon EKS 支持与 OIDC Provider 关联的新特性。 我们使用开源 OIDC Provider Dex 和 web 应用dex-k8s-authenticator 的集成提供了一个身份验证层,将 GitHub Organizations team 与 GitHub OAuth 应用程序一起用作 IdP,将 OpenID Connect (OIDC) 身份提供商 (IdP) 集成添加到 Amazon EKS。方便 Amazon EKS 用户,统一管理对集群的访问控制。

 

本篇作者

马卫军

AWS中国团队的解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,同时致力于AWS云服务在国内教育行业的应用和推广。有丰富的数据仓库以及大数据开发和架构设计经验。马卫军平时热爱爬山和足球,同时也乐于和他人分享自己的各种经历。