# 在CCE中使用Dex OIDC Provider进行身份验证
[Dex](https://dexidp.io/docs/guides/kubernetes/)是一个开源的[OpenID Connect](https://openid.net/connect/)（OIDC）身份提供商，在Kubernetes中使用Dex可以为集群提供灵活的身份认证和联邦身份管理能力。Dex充当中间层，将多种身份源（如LDAP、GitHub、SAML等）转换为标准的OIDC协议，供Kubernetes和其他应用使用。
OIDC是一种基于OAuth 2.0协议的认证方式，在使用访问令牌（Access Token）之外还会返回一个[ID Token（ID 令牌）](https://openid.net/specs/openid-connect-core-1_0.html#IDToken)。ID Token是一个由服务器签名的JWT（JSON Web Token）令牌，包含用户的邮箱地址等预知字段。Kubernetes可以根据ID Token中包含的用户信息进行RBAC授权，从而实现第三方身份源与Kubernetes权限的转换，详情请参见[OpenID Connect（OIDC）令牌](https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/authentication/#openid-connect-tokens)。
典型应用场景如下：
- **企业LDAP/AD集成**：企业内部已有LDAP，希望Kubernetes直接继承现有用户体系。
- **多集群统一认证**：多个Kubernetes集群共享同一个Dex实例，实现统一登录。
- **统一身份联邦**：多团队协作时，将不同来源的用户身份认证（如GitHub、Gitlab等）通过Dex统一转换为OIDC协议，并获取 Kubernetes可识别的OIDC Token。
本文演示使用LDAP OAuth账户的方式完成CCE OIDC的认证。
#### 方案原理
在Kubernetes集群中使用Dex进行OIDC身份验证时，主要包含Dex和dex-k8s-authenticator两个组件：
- Dex充当其他身份提供商的门户，负责将身份验证请求推送到LDAP服务器、SAML提供商或其他网络身份提供商（如 GitHub、Gitlab等）。
- dex-k8s-authenticator是一个web-app，它可以与Dex进行交互并获取Dex生成的token，然后提供创建和修改kubeconfig文件的命令。用户执行这些生成的命令后可以完成kubeconfig文件配置。
图1Dex登录验证流程   
![](https://support.huaweicloud.com/usermanual-cce/zh-cn_image_0000002273241434.png "点击放大")
使用Dex登录验证的流程如下所示：
1. 用户访问登录页面。
2. 系统会将登录请求重定向到Dex进行身份登录验证。
3. Dex将身份验证请求转发给第三方身份认证服务（Identity Provider）。
4. 如果用户的凭证通过了第三方身份认证服务的验证，身份认证服务将返回id_token。
5. 用户在使用kubectl时，将id_token设置为--token标志的值，或者将其直接添加到kubeconfig中进行使用。
6. kubectl将id_token放在HTTP请求的Authorization头部，并发起请求到Kubernetes API服务器。
7. API服务器接收到请求后，会验证Authorization头部中的JWT签名，以确认其有效性。
8. API服务器会与Dex通信以验证id_token是否已经被授权。
9. Dex确认该用户已授权，并返回验证结果。
10. 鉴权成功之后，API服务器向kubectl返回响应。
11. 最后，kubectl将API服务器的响应以可读的形式呈现给用户。
 
#### 准备工作
1. **创建CCE集群** ：在华为云控制台创建一个CCE集群，详情请参见[购买Standard/Turbo集群](https://support.huaweicloud.com/usermanual-cce/cce_10_0028.html)。集群版本要求v1.30.14-r0、v1.31.10-r0、v1.32.6-r0、v1.33.1-r0及以上。
2. **准备kubectl及Helm工具** ：在集群所在VPC内准备一台可访问公网的虚拟机，[安装kubectl连接集群](https://support.huaweicloud.com/usermanual-cce/cce_10_0107.html)，并[安装Helm v3](https://support.huaweicloud.com/usermanual-cce/cce_10_0144.html#cce_10_0144__zh-cn_topic_0226102212_zh-cn_topic_0179003017_section3719193213815)。
3. **创建ELB并绑定公网IP** ：创建一个ELB实例，并绑定一个公网IP，具体操作请参见[购买独享型负载均衡器](https://support.huaweicloud.com/usermanual-elb/elb_lb_000006.html)。
4. **准备域名** ：
   - 公网域名1：dex.k8s.example.com，此域名为dex服务的访问域名地址。
   
   - 公网域名2：login.k8s.example.com，此域名为dex-k8s-authenticator服务的域名地址。
    
5. **配置DNS A记录** ：为上述两个域名配置DNS公网解析，具体操作请参见[配置公网域名解析](https://support.huaweicloud.com/usermanual-dns/dns_usermanual_0006.html)。如果仅使用内网访问该域名则可以通过节点host进行配置。
6. **安装Nginx Ingress插件** ：选择[步骤3]中创建的ELB实例，详情请参见[NGINX Ingress控制器](https://support.huaweicloud.com/usermanual-cce/cce_10_0034.html)。
7. **已有LDAP服务**：确保LDAP服务已部署，并创建好用户组和用户。
8. **（可选）节点子网配置SNAT：** 如果Dex部署在其他集群，需要为集群所在VPC和节点所在子网创建公网NAT网关，允许kube-apiserver访问公网。具体操作请参见[购买公网NAT网关](https://support.huaweicloud.com/usermanual-natgateway/zh-cn_topic_0150270259.html)。
 
 #### 步骤一：创建密钥（已有证书请忽略）
1. 登录已安装kubectl和Helm的虚拟机。
2. 创建Dex自签证书。如果通过HTTPS访问Dex需要证书认证，因此需要先自签名服务器证书和CA证书。 
   创建create_cert.sh脚本文件，文件内容如下：
   ```
   #!/bin/bash
   mkdir -p ssl
   cat << EOF > ssl/req.cnf
   [req]
   req_extensions = v3_req
   distinguished_name = req_distinguished_name
   [req_distinguished_name]
   [ v3_req ]
   basicConstraints = CA:FALSE
   keyUsage = nonRepudiation, digitalSignature, keyEncipherment
   subjectAltName = @alt_names
   [alt_names]
   DNS.1 = *.k8s.example.com  #  所有k8s.example.com后缀的域名都是此证书的信任范围
   EOF
   openssl genrsa -out ssl/ca-key.pem 2048
   openssl req -x509 -new -nodes -key ssl/ca-key.pem -days 3650 -out ssl/ca.pem -subj "/CN=kube-ca"
   openssl genrsa -out ssl/key.pem 2048
   openssl req -new -key ssl/key.pem -out ssl/csr.pem -subj "/CN=kube-ca" -config ssl/req.cnf
   openssl x509 -req -in ssl/csr.pem -CA ssl/ca.pem -CAkey ssl/ca-key.pem -CAcreateserial -out ssl/cert.pem -days 3650 -extensions v3_req -extfile ssl/req.cnf
   ```
   执行脚本：
   ```
   chmod +x create_cert.sh
   ./create_cert.sh
   ```
   
   
3. 生成服务器证书Secret，访问 dex.k8s.example.com 和 login.k8s.example.com 需要使用该密钥。本示例中密钥名称为*dex.example.com.tls* 。
   
   ```
   kubectl create ns dex
   cd ssl; mv key.pem tls.key; mv cert.pem tls.crt
   kubectl create secret tls -n dex dex.example.com.tls \
      --cert=tls.crt\
      --key=tls.key
   ```
   
   
 
 #### 步骤二：部署Dex应用
使用Helm部署Dex应用，操作详情请参见[通过Dex进行Kubernetes身份验证](https://dexidp.io/docs/guides/kubernetes/)。
1. 登录已安装kubectl和Helm的虚拟机，添加Helm仓库。 
   ```
   helm repo add dex https://charts.dexidp.io
   helm repo update
   ```
   
   
2. 创建dex-values.yaml文件，用于自定义配置Dex参数，该文件中定义了Dex的访问方式和Dex中注册的LDAP后端服务。 
   文件示例如下：
   ```
   tls: 
     enabled: true 
     clientCA: "" 
   ingress: 
     enabled: true 
     className: nginx   # 创建Nginx Ingress
     hosts: 
       - host: dex.k8s.example.com   # Dex的访问域名
         paths: 
           - path: / 
             pathType: ImplementationSpecific 
     tls: 
       - secretName: dex.example.com.tls  # 步骤一中创建Dex的访问密钥
         hosts: 
           - dex.k8s.example.com   # Dex的访问域名
   config: 
     issuer: https://dex.k8s.example.com   # Dex的访问域名，访问地址也可以填http 
     storage: 
       type: kubernetes 
       config: 
         inCluster: true 
     oauth2:
       responseTypes: ["code", "token", "id_token"] 
       skipApprovalScreen: true 
     connectors: 
      - type: ldap 
        id: ldap 
        name: LDAP 
        config:  
          host: xxx.xxx.xxx.xxx:389 # ldap server 
          insecureNoSSL: true 
          insecureSkipVerify: true 
          bindDN: CN=admin,DC=example,DC=com # 管理员DN(Distinguished Name)，是LDAP目录中的唯一标识符
          bindPW: "*****" # 请设置管理员密码
          userSearch: # 查询LDAP中的用户信息映射到Dex中
            baseDN: dc=example,dc=com 
            filter: "(objectClass=posixAccount)" 
            username: uid  # 用户登录名
            idAttr: DN # 本示例中将LDAP记录中的DN映射到Dex
            emailAttr: mail # 本示例中将LDAP记录中的mail字段映射到Dex
            nameAttr: cn # 本示例中将LDAP记录中的cn字段映射到Dex
          groupSearch: 
            baseDN: dc=example,dc=com 
            filter: "(objectClass=posixGroup)" 
            userMatchers: 
            - userAttr: uid 
              groupAttr: memberUid 
            nameAttr: cn 
     staticClients: 
       - id: kubernetes    # 注册客户端ID
         secret: *****    # 设置客户端密码
         name: "kubernetes" 
         redirectURIs: 
          - https://login.k8s.example.com/callback   # dex-k8s-authenticator的访问域名
   ```
   更多参数配置请参考官方示例：
   - Dex示例：[Authentication Through an OAuth 2.0 Provider](https://dexidp.io/docs/connectors/oauth/)
   
   - LDAP示例：[Authentication Through LDAP](https://dexidp.io/docs/connectors/ldap/)
   
   
   
   
3. 根据自定义配置安装Dex。 
   ```
   helm install dex dex/dex --namespace dex --create-namespace --version 0.19.1 --values dex-values.yaml
   ```
   执行以下命令查看已安装的模板实例。
   ```
   helm list
   ```
   
   
 
#### 步骤三：配置集群内域名解析
1. 登录[CCE控制台](https://console.huaweicloud.com/cce2.0/?#/cce/cluster/list)，单击集群名称进入集群。
2. 在左侧导航栏中选择"插件中心"，在CoreDNS 域名解析下单击"编辑"，进入插件详情页。
3. 在"参数配置"下编辑"扩展参数配置"，在plugins字段添加以下内容，增加Dex服务域名解析。 
   ```
   {
     "configBlock": "10.247.82.158 dex.k8s.example.com\nfallthrough", 
     "name": "hosts"
   }
   ```
   其中IP *10.247.82.158*为nginx-ingress-controller Service的ClusterIP。
   ![](https://support.huaweicloud.com/usermanual-cce/zh-cn_image_0000002309212161.png "点击放大")
   
   
   
4. 单击"确定"。
 
#### 步骤四：部署dex-k8s-authenticator应用
1. 添加Helm仓库。 
   ```
   helm repo add skm https://charts.sagikazarmark.dev
   helm repo update
   ```
   
   
2. 创建authen-values.yaml文件，用于自定义配置dex-k8s-authenticator参数。配置示例详情请参见<https://github.com/mintel/dex-k8s-authenticator/blob/master/docs/config.md>。
   
   ```
   config: 
     clusters: 
       - name: Hello-CCE 
         short_description: "Your cluster" 
         description: "Your cluster" 
         issuer: https://dex.k8s.example.com    # Dex的访问域名
         client_id: kubernetes                  # 对应步骤二中Dex config中的client_id 
         client_secret: *****                   # 对应步骤二中Dex config中的client_secret 
         redirect_uri: https://login.k8s.example.com/callback        # dex-k8s-authenticator的访问域名
         k8s_master_uri: https://192.168.0.158:5443                  # 集群API Server访问地址 
         #集群的CA证书
         k8s_ca_pem: | 
           -----BEGIN CERTIFICATE----- 
           ...
           -----END CERTIFICATE----- 
     # 如果Dex访问为https, 需要提供Dex域名的CA证书
     trusted_root_ca: |
       -----BEGIN CERTIFICATE----- 
       ...
       -----END CERTIFICATE----- 
   ingress: 
     enabled: true 
     className: nginx 
     hosts: 
       - host: login.k8s.example.com # 修改为dex-k8s-authenticator的访问域名
         paths: 
           - path: / 
             pathType: ImplementationSpecific 
     tls: 
       - secretName: dex.example.com.tls  # 步骤一中创建Dex的访问密钥
         hosts: 
           - login.k8s.example.com    # 修改为dex-k8s-authenticator的访问域名
   ```
   
   
3. 根据自定义配置安装dex-k8s-authenticator。 
   ```
   helm install dex-k8s-authenticator skm/dex-k8s-authenticator --namespace dex --version 0.0.3 --values authen-values.yaml
   ```
   
   
 
 #### 步骤五：修改APIserver启动参数
1. 登录[CCE控制台](https://console.huaweicloud.com/cce2.0/?#/cce/cluster/list)，单击集群名称进入集群。
2. 在集群控制台左侧导航栏中选择"配置中心"。
3. 切换至"集群访问配置"页签，启用OIDC，并配置kube-apiserver使用OIDC所需的参数。 
   
   | 参数                            | 说明                                                                                                                                                                                                 | 示例                                                                             |
   |:---|:---|:---|
   | 发布者URL (oidc-issuer-url)   | 提供OpenID Connect认证服务的URL，必须是HTTPS协议。                                                                                                                                                                  | https://dex.k8s.example.com                                                     |
   | 客户端ID (oidc-client-id)     | OpenID Connect认证服务中注册的客户端ID，例如[步骤二]中注册的客户端ID为kubernetes。                                                                                                       | kubernetes                                                                   |
   | 注册用户名 (oidc-username-claim) | 指定JWT令牌中的字段，获取该字段的值作为用户名。默认值为sub，这通常是最终用户的唯一标识符，您也可以选择其他字段，如email或name。 后续可以在集群中根据用户名授予Kubernetes权限，参见[步骤六：为第三方用户授予Kubernetes权限]。 | email 该参数值设置为email，表示将JWT中email字段的值，即电子邮件地址作为用户名。 |
   | 注册组 (oidc-groups-claim)     | 指定JWT令牌中的字段，获取该字段的值作为用户组，表示用户组的字段名称通常为groups。后续可以根据用户组授予Kubernetes权限，参见[步骤六：为第三方用户授予Kubernetes权限]。                                                               | groups 该参数值设置为groups，表示将JWT中groups字段的值作为用户组。     |
   | 认证CA证书 (oidc-ca-pem)         | PEM格式的CA证书，用于签署身份提供商的Web证书。                                                                                                                                                                           | [步骤一]中Dex域名的CA证书                            |
      
   ![](https://support.huaweicloud.com/usermanual-cce/zh-cn_image_0000002309250673.png "点击放大")
   
   
   
4. 单击"确认配置"。
 
 #### 步骤六：为第三方用户授予Kubernetes权限
由于Dex只是对用户进行认证，并没有Kubernetes授权，所以需要为经过Dex认证的用户添加Kubernetes权限。
本示例中，根据[步骤五]中设置的注册组groups进行授权，即对认证返回的JWT中的用户组授予Kubernetes权限（本示例中用户组名称为CCE）。如果登录用户属于该用户组，则具有相应的Kubernetes权限。配置ClusterRoleBinding和ClusterRole的示例如下，您可以根据自己的实际需求分配对应的权限：
```
kind: ClusterRoleBinding 
apiVersion: rbac.authorization.k8s.io/v1 
metadata: 
  name: cce-admin 
subjects: 
- kind: Group 
  name: "CCE"  # CCE用户组是LDAP中用户所属用户组，为该用户组中的用户授权Kubernetes权限
  apiGroup: rbac.authorization.k8s.io 
roleRef: 
  kind: ClusterRole 
  name: cluster-admin 
   apiGroup: rbac.authorization.k8s.io
```
#### 步骤七：登录测试
1. 在浏览器中打开dex-k8s-authenticator域名，本示例中为login.k8s.example.com。
2. 输入LDAP中CCE用户组下的用户账号密码。
3. 登录成功后，dex-k8s-authenticator会提供可执行的命令，帮助用户配置kubeconfig，请按照页面指导执行命令。 
   ![](https://support.huaweicloud.com/usermanual-cce/zh-cn_image_0000002273545930.png "点击放大")
   
   
4. 执行以上命令，完成kubeconfig配置后，使用kubectl访问Kubernetes资源进行测试。 
   ![](https://support.huaweicloud.com/usermanual-cce/zh-cn_image_0000002273546534.png "点击放大")
   
   
 
