×

当在Azure上运行的OpenShift Container Platform集群处于**工作负载标识/联合标识**模式时,这意味着集群正在利用Azure和OpenShift Container Platform的功能,在应用程序级别应用Microsoft Entra工作负载ID中的用户分配的托管标识应用程序注册

云凭据运算符(CCO)是默认安装在在云提供商上运行的OpenShift Container Platform集群中的集群运算符。从OpenShift Container Platform 4.14.8开始,CCO支持使用工作负载ID的OLM管理的运算符的工作流。

出于工作负载ID的目的,CCO提供以下功能:

  • 检测它是否在启用工作负载 ID 的集群上运行

  • 检查CredentialsRequest对象中是否存在提供授予操作员访问 Azure 资源所需信息的字段

CCO 可以通过扩展使用CredentialsRequest对象来半自动化此过程,该对象可以请求创建包含工作负载 ID 工作流所需信息的Secrets

不建议使用自动批准更新的订阅,因为在更新之前可能需要进行权限更改。使用手动批准更新的订阅可确保管理员有机会验证更高版本的权限,采取必要的步骤,然后进行更新。

作为准备在 OpenShift Container Platform 4.14 及更高版本中与更新的 CCO 一起使用的操作员作者,您应该指导用户并添加代码以处理与早期 CCO 版本的差异,以及处理工作负载 ID 令牌身份验证(如果您的操作员尚未启用)。推荐的方法是提供一个填写了正确的工作负载 ID 字段的CredentialsRequest对象,并让 CCO 为您创建Secret对象。

如果您计划支持低于 4.14 版本的 OpenShift Container Platform 集群,请考虑向用户提供有关如何使用 CCO 实用程序 (ccoctl) 手动创建包含启用工作负载 ID 信息的密钥的说明。早期版本的 CCO 无法识别集群上的工作负载 ID 模式,因此无法为您创建密钥。

您的代码应检查从未出现的密钥,并警告用户遵循您提供的回退说明。

使用工作负载 ID 进行身份验证需要以下信息:

  • azure_client_id

  • azure_tenant_id

  • azure_region

  • azure_subscription_id

  • azure_federated_token_file

Web 控制台中的**安装 Operator**页面允许集群管理员在安装时提供此信息。然后,此信息将作为环境变量传播到 Operator pod 的Subscription对象中。

启用 Operator 以支持使用 Microsoft Entra 工作负载 ID 的基于 CCO 的工作流

作为设计项目在 Operator Lifecycle Manager (OLM) 上运行的操作员作者,您可以通过自定义项目以支持云凭据操作员 (CCO) 来启用您的 Operator 对启用 Microsoft Entra 工作负载 ID 的 OpenShift Container Platform 集群进行身份验证。

使用此方法,Operator 负责并需要创建CredentialsRequest对象和读取生成的Secret对象的 RBAC 权限。

默认情况下,与 Operator 部署相关的 pod 挂载serviceAccountToken卷,以便可以在生成的Secret对象中引用服务帐户令牌。

先决条件
  • OpenShift Container Platform 4.14 或更高版本

  • 处于工作负载 ID 模式的集群

  • 基于 OLM 的 Operator 项目

步骤
  1. 更新 Operator 项目的ClusterServiceVersion (CSV) 对象

    1. 确保您的 Operator 具有创建CredentialsRequests对象的 RBAC 权限

      clusterPermissions 列表示例
      # ...
      install:
        spec:
          clusterPermissions:
          - rules:
            - apiGroups:
              - "cloudcredential.openshift.io"
              resources:
              - credentialsrequests
              verbs:
              - create
              - delete
              - get
              - list
              - patch
              - update
              - watch
    2. 添加以下注释以声明支持此基于 CCO 的使用工作负载 ID 的工作流方法

      # ...
      metadata:
       annotations:
         features.operators.openshift.io/token-auth-azure: "true"
  2. 更新您的 Operator 项目代码

    1. Subscription对象在 pod 上设置的环境变量中获取客户端 ID、租户 ID 和订阅 ID。例如:

      // Get ENV var
      clientID := os.Getenv("CLIENTID")
      tenantID := os.Getenv("TENANTID")
      subscriptionID := os.Getenv("SUBSCRIPTIONID")
      azureFederatedTokenFile := "/var/run/secrets/openshift/serviceaccount/token"
    2. 确保您已准备好要修补和应用的CredentialsRequest对象。

      目前不支持将CredentialsRequest对象添加到 Operator 包中。

    3. 将 Azure 凭据信息和 Web 身份令牌路径添加到凭据请求,并在 Operator 初始化期间应用它

      Operator 初始化期间应用CredentialsRequest对象的示例
      // apply CredentialsRequest on install
      credReqTemplate.Spec.AzureProviderSpec.AzureClientID = clientID
      credReqTemplate.Spec.AzureProviderSpec.AzureTenantID = tenantID
      credReqTemplate.Spec.AzureProviderSpec.AzureRegion = "centralus"
      credReqTemplate.Spec.AzureProviderSpec.AzureSubscriptionID = subscriptionID
      credReqTemplate.CloudTokenPath = azureFederatedTokenFile
      
      c := mgr.GetClient()
      if err := c.Create(context.TODO(), credReq); err != nil {
          if !errors.IsAlreadyExists(err) {
              setupLog.Error(err, "unable to create CredRequest")
              os.Exit(1)
          }
      }
    4. 确保您的 Operator 可以等待 CCO 显示Secret对象,如下面的示例所示,该示例与您在 Operator 中协调的其他项目一起调用

      等待Secret对象的示例
      // WaitForSecret is a function that takes a Kubernetes client, a namespace, and a v1 "k8s.io/api/core/v1" name as arguments
      // It waits until the secret object with the given name exists in the given namespace
      // It returns the secret object or an error if the timeout is exceeded
      func WaitForSecret(client kubernetes.Interface, namespace, name string) (*v1.Secret, error) {
        // set a timeout of 10 minutes
        timeout := time.After(10 * time.Minute) (1)
      
        // set a polling interval of 10 seconds
        ticker := time.NewTicker(10 * time.Second)
      
        // loop until the timeout or the secret is found
        for {
           select {
           case <-timeout:
              // timeout is exceeded, return an error
              return nil, fmt.Errorf("timed out waiting for secret %s in namespace %s", name, namespace)
                 // add to this error with a pointer to instructions for following a manual path to a Secret that will work on STS
           case <-ticker.C:
              // polling interval is reached, try to get the secret
              secret, err := client.CoreV1().Secrets(namespace).Get(context.Background(), name, metav1.GetOptions{})
              if err != nil {
                 if errors.IsNotFound(err) {
                    // secret does not exist yet, continue waiting
                    continue
                 } else {
                    // some other error occurred, return it
                    return nil, err
                 }
              } else {
                 // secret is found, return it
                 return secret, nil
              }
           }
        }
      }
      1 timeout值基于对 CCO 检测添加的CredentialsRequest对象并生成Secret对象的速度的估计。您可能需要考虑缩短时间或为可能想知道 Operator 为什么尚未访问云资源的集群管理员创建自定义反馈。
    5. 读取 CCO 从CredentialsRequest对象创建的密钥以使用 Azure 进行身份验证并接收必要的凭据。