5.10. トークン認証


5.10.1. クラウドプロバイダー上の Operator のトークン認証

多くのクラウドプロバイダーは、短期的で権限が限定されたセキュリティー認証情報を提供するアカウントトークンを使用して認証を有効にできます。

OpenShift Container Platform には、クラウドプロバイダーの認証情報をカスタムリソース定義 (CRD) として管理するための Cloud Credential Operator (CCO) が含まれています。CCO は CredentialsRequest カスタムリソース (CR) と同期して、OpenShift Container Platform コンポーネントが必要な特定のパーミッションを持つクラウドプロバイダーの認証情報をリクエストできるようにします。

以前は、CCO が 手動モード のクラスターでは、Operator Lifecycle Manager (OLM) によって管理される Operator が、ユーザーが必要なクラウド認証情報を手動でプロビジョニングする方法に関する詳細な手順を OperatorHub に提供することがよくありました。

OpenShift Container Platform 4.14 以降、CCO は、特定のクラウドプロバイダーで短期認証情報の使用が有効になっているクラスター上で CCO が実行していることを検出できるようになりました。その後、Operator の作成者が Operator が更新された CCO をサポートできるようにしている場合は、特定の認証情報のプロビジョニングを半自動化できます。

5.10.2. AWS STS を使用した OLM 管理 Operator 向けの CCO ベースのワークフロー

AWS 上で実行している OpenShift Container Platform クラスターが Security Token Service (STS) モードである場合、クラスターは AWS と OpenShift Container Platform の機能を利用して、アプリケーションレベルで IAM ロールを使用していることを意味します。STS を使用すると、アプリケーションは IAM ロールを引き受けることができる JSON Web トークン (JWT) を提供できます。

JWT には、サービスアカウントに一時的に許可されるパーミッションを許可する sts:AssumeRoleWithWebIdentity IAM アクションの Amazon Resource Name (ARN) が含まれています。JWT には、AWS IAM が検証できる ProjectedServiceAccountToken の署名キーが含まれています。署名されたサービスアカウントトークン自体は、AWS ロールを引き受けるために必要な JWT として使用されます。

Cloud Credential Operator (CCO) は、クラウドプロバイダー上で実行している OpenShift Container Platform クラスターにデフォルトでインストールされる Cluster Operator です。CCO は STS のために次の機能を提供します。

  • CCO が STS 対応のクラスター上で実行されているかどうかを検出する
  • CredentialsRequest オブジェクトをチェックして、Operator に AWS リソースへのアクセスを許可するために必要な情報を提供するフィールドが存在するかどうかを確認する

CCO は、手動モードの場合でもこの検出を実行します。適切に設定されている場合、CCO は必要なアクセス情報を含む Secret オブジェクトを Operator namespace に投影します。

OpenShift Container Platform 4.14 以降、CCO は、STS ワークフローに必要な情報を含む Secrets の作成を要求できる CredentialsRequest オブジェクトの使用を拡張することで、このタスクを半自動化できるようになりました。ユーザーは、Web コンソールまたは CLI から Operator をインストールするときにロール ARN を指定できます。

注記

更新の自動承認を使用したサブスクリプションは推奨されません。更新前に権限の変更が必要な場合があるためです。更新の手動承認を使用したサブスクリプションであれば、管理者が新しいバージョンの権限を確認し、必要な手順を実行してから更新できます。

OpenShift Container Platform 4.14 以降の更新された CCO と一緒に使用するために Operator を準備する Operator 作成者は、STS トークン認証の処理に加えて、ユーザーに指示し、以前の CCO バージョンからの相違を処理するコードを追加する必要があります (Operator がまだ STS 未対応の場合)。推奨される方法は、STS 関連のフィールドを正しく入力した CredentialsRequest オブジェクトを用意して、CCO に Secret を作成させることです。

重要

バージョン 4.14 より前の OpenShift Container Platform クラスターをサポートする予定がる場合は、CCO ユーティリティー (ccoctl) を使用して STS 対応情報を含むシークレットを手動で作成する方法をユーザーに提供することを検討してください。以前の CCO バージョンはクラスター上の STS モードを認識しないため、シークレットを作成できません。

コードでは、決して表示されないシークレットをチェックし、提供したフォールバック手順に従うようにユーザーに警告する必要があります。詳細は、「代替方法」サブセクションを参照してください。

5.10.2.1. Operator が AWS STS を使用した CCO ベースのワークフローをサポートできるようにする

Operator Lifecycle Manager (OLM) で実行するプロジェクトを設計する Operator 作成者は、Cloud Credential Operator (CCO) をサポートするようにプロジェクトをカスタマイズすることで、STS 対応の OpenShift Container Platform クラスター上で Operator が AWS に対して認証できるようにすることができます。

この方法では、Operator が CredentialsRequest オブジェクトを作成します。Operator には、オブジェクトを作成するための RBAC 権限と、生成される Secret オブジェクトを読み取るための RBAC 権限が必要です。

注記

デフォルトでは、Operator デプロイメントに関連する Pod は、生成される Secret オブジェクトでサービスアカウントトークンを参照できるように、serviceAccountToken ボリュームをマウントします。

前提条件

  • OpenShift Container Platform 4.14 以降
  • STS モードのクラスター
  • OLM ベースの Operator プロジェクト

手順

  1. Operator プロジェクトの ClusterServiceVersion (CSV) オブジェクトを更新します。

    1. Operator が CredentialsRequests オブジェクトを作成する RBAC 権限を持っていることを確認します。

      例5.16 clusterPermissions リストの例

      # ...
      install:
        spec:
          clusterPermissions:
          - rules:
            - apiGroups:
              - "cloudcredential.openshift.io"
              resources:
              - credentialsrequests
              verbs:
              - create
              - delete
              - get
              - list
              - patch
              - update
              - watch
    2. AWS STS を使用したこの CCO ベースのワークフロー方式のサポートを要求するために、次のアノテーションを追加します。

      # ...
      metadata:
       annotations:
         features.operators.openshift.io/token-auth-aws: "true"
  2. Operator プロジェクトコードを更新します。

    1. Subscription オブジェクトによって Pod に設定された環境変数からロール ARN を取得します。以下に例を示します。

      // Get ENV var
      roleARN := os.Getenv("ROLEARN")
      setupLog.Info("getting role ARN", "role ARN = ", roleARN)
      webIdentityTokenPath := "/var/run/secrets/openshift/serviceaccount/token"
    2. パッチを適用して適用できる CredentialsRequest オブジェクトがあることを確認してください。以下に例を示します。

      例5.17 CredentialsRequest オブジェクトの作成例

      import (
         minterv1 "github.com/openshift/cloud-credential-operator/pkg/apis/cloudcredential/v1"
         corev1 "k8s.io/api/core/v1"
         metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
      )
      
      var in = minterv1.AWSProviderSpec{
         StatementEntries: []minterv1.StatementEntry{
            {
               Action: []string{
                  "s3:*",
               },
               Effect:   "Allow",
               Resource: "arn:aws:s3:*:*:*",
            },
         },
      	STSIAMRoleARN: "<role_arn>",
      }
      
      var codec = minterv1.Codec
      var ProviderSpec, _ = codec.EncodeProviderSpec(in.DeepCopyObject())
      
      const (
         name      = "<credential_request_name>"
         namespace = "<namespace_name>"
      )
      
      var CredentialsRequestTemplate = &minterv1.CredentialsRequest{
         ObjectMeta: metav1.ObjectMeta{
             Name:      name,
             Namespace: "openshift-cloud-credential-operator",
         },
         Spec: minterv1.CredentialsRequestSpec{
            ProviderSpec: ProviderSpec,
            SecretRef: corev1.ObjectReference{
               Name:      "<secret_name>",
               Namespace: namespace,
            },
            ServiceAccountNames: []string{
               "<service_account_name>",
            },
            CloudTokenPath:   "",
         },
      }

      あるいは、YAML 形式の CredentialsRequest オブジェクトから開始している場合 (たとえば、Operator プロジェクトコードの一部として)、別の方法で処理することもできます。

      例5.18 YAML フォームでの CredentialsRequest オブジェクト作成の例

      // CredentialsRequest is a struct that represents a request for credentials
      type CredentialsRequest struct {
        APIVersion string `yaml:"apiVersion"`
        Kind       string `yaml:"kind"`
        Metadata   struct {
           Name      string `yaml:"name"`
           Namespace string `yaml:"namespace"`
        } `yaml:"metadata"`
        Spec struct {
           SecretRef struct {
              Name      string `yaml:"name"`
              Namespace string `yaml:"namespace"`
           } `yaml:"secretRef"`
           ProviderSpec struct {
              APIVersion     string `yaml:"apiVersion"`
              Kind           string `yaml:"kind"`
              StatementEntries []struct {
                 Effect   string   `yaml:"effect"`
                 Action   []string `yaml:"action"`
                 Resource string   `yaml:"resource"`
              } `yaml:"statementEntries"`
              STSIAMRoleARN   string `yaml:"stsIAMRoleARN"`
           } `yaml:"providerSpec"`
      
           // added new field
            CloudTokenPath   string `yaml:"cloudTokenPath"`
        } `yaml:"spec"`
      }
      
      // ConsumeCredsRequestAddingTokenInfo is a function that takes a YAML filename and two strings as arguments
      // It unmarshals the YAML file to a CredentialsRequest object and adds the token information.
      func ConsumeCredsRequestAddingTokenInfo(fileName, tokenString, tokenPath string) (*CredentialsRequest, error) {
        // open a file containing YAML form of a CredentialsRequest
        file, err := os.Open(fileName)
        if err != nil {
           return nil, err
        }
        defer file.Close()
      
        // create a new CredentialsRequest object
        cr := &CredentialsRequest{}
      
        // decode the yaml file to the object
        decoder := yaml.NewDecoder(file)
        err = decoder.Decode(cr)
        if err != nil {
           return nil, err
        }
      
        // assign the string to the existing field in the object
        cr.Spec.CloudTokenPath = tokenPath
      
        // return the modified object
        return cr, nil
      }
      注記

      CredentialsRequest オブジェクトを Operator バンドルに追加することは現在サポートされていません。

    3. ロール ARN と Web ID トークンパスを認証情報リクエストに追加し、Operator の初期化中に適用します。

      例5.19 Operator の初期化中に CredentialsRequest オブジェクトを適用する例

      // apply CredentialsRequest on install
      credReq := credreq.CredentialsRequestTemplate
      credReq.Spec.CloudTokenPath = webIdentityTokenPath
      
      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 で調整している他の項目とともに呼び出されます。

      例5.20 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 によって作成されたシークレットを読み取り、そのシークレットのデータを含む AWS 設定ファイルを作成することで、AWS 設定をセットアップします。

      例5.21 AWS 設定の作成例

      func SharedCredentialsFileFromSecret(secret *corev1.Secret) (string, error) {
         var data []byte
         switch {
         case len(secret.Data["credentials"]) > 0:
             data = secret.Data["credentials"]
         default:
             return "", errors.New("invalid secret for aws credentials")
         }
      
      
         f, err := ioutil.TempFile("", "aws-shared-credentials")
         if err != nil {
             return "", errors.Wrap(err, "failed to create file for shared credentials")
         }
         defer f.Close()
         if _, err := f.Write(data); err != nil {
             return "", errors.Wrapf(err, "failed to write credentials to %s", f.Name())
         }
         return f.Name(), nil
      }
      重要

      シークレットは存在すると想定されますが、このシークレットを使用する場合、CCO がシークレットを作成する時間を与えるために、Operator コードは待機して再試行する必要があります。

      さらに、待機期間は最終的にタイムアウトになり、OpenShift Container Platform クラスターのバージョン、つまり CCO が、STS 検出による CredentialsRequest オブジェクトのワークフローをサポートしていない以前のバージョンである可能性があることをユーザーに警告します。このような場合は、別の方法を使用してシークレットを追加する必要があることをユーザーに指示します。

    6. AWS SDK セッションを設定します。以下に例を示します。

      例5.22 AWS SDK セッション設定の例

      sharedCredentialsFile, err := SharedCredentialsFileFromSecret(secret)
      if err != nil {
         // handle error
      }
      options := session.Options{
         SharedConfigState: session.SharedConfigEnable,
         SharedConfigFiles: []string{sharedCredentialsFile},
      }

5.10.2.2. ロールの指定

Operator の説明には、インストール前に作成する必要があるロールの詳細を、理想的には管理者が実行できるスクリプトの形式で含める必要があります。以下に例を示します。

例5.23 ロール作成スクリプトの例

#!/bin/bash
set -x

AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
OIDC_PROVIDER=$(oc get authentication cluster -ojson | jq -r .spec.serviceAccountIssuer | sed -e "s/^https:\/\///")
NAMESPACE=my-namespace
SERVICE_ACCOUNT_NAME="my-service-account"
POLICY_ARN_STRINGS="arn:aws:iam::aws:policy/AmazonS3FullAccess"


read -r -d '' TRUST_RELATIONSHIP <<EOF
{
 "Version": "2012-10-17",
 "Statement": [
   {
     "Effect": "Allow",
     "Principal": {
       "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
     },
     "Action": "sts:AssumeRoleWithWebIdentity",
     "Condition": {
       "StringEquals": {
         "${OIDC_PROVIDER}:sub": "system:serviceaccount:${NAMESPACE}:${SERVICE_ACCOUNT_NAME}"
       }
     }
   }
 ]
}
EOF

echo "${TRUST_RELATIONSHIP}" > trust.json

aws iam create-role --role-name "$SERVICE_ACCOUNT_NAME" --assume-role-policy-document file://trust.json --description "role for demo"

while IFS= read -r POLICY_ARN; do
   echo -n "Attaching $POLICY_ARN ... "
   aws iam attach-role-policy \
       --role-name "$SERVICE_ACCOUNT_NAME" \
       --policy-arn "${POLICY_ARN}"
   echo "ok."
done <<< "$POLICY_ARN_STRINGS"

5.10.2.3. トラブルシューティング

5.10.2.3.1. 認証失敗

認証が成功しなかった場合は、Operator に提供されたトークンを使用して、Web ID でロールを引き受けることができることを確認してください。

手順

  1. Pod からトークンを抽出します。

    $ oc exec operator-pod -n <namespace_name> \
        -- cat /var/run/secrets/openshift/serviceaccount/token
  2. Pod からロール ARN を抽出します。

    $ oc exec operator-pod -n <namespace_name> \
        -- cat /<path>/<to>/<secret_name> 1
    1
    パスに root を使用しないでください。
  3. Web ID トークンを使用してロールを引き受けてみます。

    $ aws sts assume-role-with-web-identity \
        --role-arn $ROLEARN \
        --role-session-name <session_name> \
        --web-identity-token $TOKEN
5.10.2.3.2. Secret が正しくマウントされていない

非 root ユーザーとして実行する Pod は、デフォルトで AWS 共有認証情報ファイルが存在すると想定される /root ディレクトリーに書き込むことができません。シークレットが AWS 認証情報ファイルのパスに正しくマウントされていない場合は、シークレットを別の場所にマウントし、AWS SDK で共有認証情報ファイルオプションを有効にすることを検討してください。

5.10.2.4. 代替方法

Operator 作成者向けの代替方法として、Operator をインストールする前に、ユーザーが Cloud Credential Operator (CCO) の CredentialsRequest オブジェクトを作成する責任があることを示すことができます。

Operator の指示では、ユーザーに次のことを示す必要があります。

  • 手順に YAML をインラインで指定するか、ユーザーにダウンロード場所を示すことで、CredentialsRequest オブジェクトの YAML バージョンを提供します。
  • ユーザーに CredentialsRequest オブジェクトを作成するように指示します。

OpenShift Container Platform 4.14 以降では、適切な STS 情報が追加された CredentialsRequest オブジェクトがクラスター上に表示されると、Operator は CCO が生成した Secret を読み取るか、クラスターサービスバージョン (CSV) でマウントを定義してマウントすることができます。

OpenShift Container Platform の以前のバージョンでは、Operator の指示でユーザーに次のことも示す必要があります。

  • CCO ユーティリティー (ccoctl) を使用して、CredentialsRequest オブジェクトから Secret YAML オブジェクトを生成します。
  • Secret オブジェクトを適切な namespace のクラスターに適用します。

Operator は、クラウド API と通信するために、結果として得られるシークレットを利用できる必要があります。この場合、シークレットは Operator がインストールされる前にユーザーによって作成されるため、Operator は次のいずれかを実行できます。

  • CSV 内の Deployment オブジェクトで明示的なマウントを定義します。
  • 推奨される「AWS STS を使用して Operator が CCO ベースのワークフローをサポートできるようにする」方法に示すように、API サーバーからプログラムで Secret オブジェクトを読み取ります。

5.10.3. Microsoft Entra Workload ID を使用した OLM 管理 Operator 向けの CCO ベースのワークフロー

Azure 上で実行されている OpenShift Container Platform クラスターが Workload Identity/Federated Identity モードである場合、そのクラスターは、Azure と OpenShift Container Platform の機能を利用して、Microsoft Entra Workload ID の ユーザー割り当てマネージド ID または アプリケーション登録 をアプリケーションレベルで適用しています。

Cloud Credential Operator (CCO) は、クラウドプロバイダー上で実行している OpenShift Container Platform クラスターにデフォルトでインストールされる Cluster Operator です。OpenShift Container Platform 4.14.8 以降、CCO は Workload ID を使用した OLM 管理 Operator のワークフローをサポートします。

CCO は Workload ID のために次の機能を提供します。

  • CCO が Workload ID 対応のクラスター上で実行されているかどうかを検出する
  • CredentialsRequest オブジェクトをチェックして、Operator に Azure リソースへのアクセスを許可するために必要な情報を提供するフィールドが存在するかどうかを確認する

CCO は、CredentialsRequest オブジェクトの使用を拡張することで、このプロセスを半自動化できます。このオブジェクトにより、Workload ID ワークフローに必要な情報を含む Secrets の作成を要求できます。

注記

更新の自動承認を使用したサブスクリプションは推奨されません。更新前に権限の変更が必要な場合があるためです。更新の手動承認を使用したサブスクリプションであれば、管理者が新しいバージョンの権限を確認し、必要な手順を実行してから更新できます。

Operator 作成者は、OpenShift Container Platform 4.14 以降の更新された CCO と一緒に使用する Operator を準備する際に、Workload ID トークン認証への対処 (Operator がまだ未対応の場合) に加えて、ユーザーに指示し、以前の CCO バージョンからの相違を処理するコードを追加する必要があります。推奨される方法は、Workload ID 関連のフィールドを正しく入力した CredentialsRequest オブジェクトを用意して、CCO に Secret オブジェクトを作成させることです。

重要

バージョン 4.14 より前の OpenShift Container Platform クラスターをサポートする予定がる場合は、CCO ユーティリティー (ccoctl) を使用して Workload ID 対応情報を含むシークレットを手動で作成する方法をユーザーに提供することを検討してください。以前の CCO バージョンはクラスター上の Workload ID モードを認識しないため、シークレットを作成できません。

コードでは、決して表示されないシークレットをチェックし、提供したフォールバック手順に従うようにユーザーに警告する必要があります。

Workload ID による認証には次の情報が必要です。

  • azure_client_id
  • azure_tenant_id
  • azure_region
  • azure_subscription_id
  • azure_federated_token_file

クラスター管理者は、Web コンソールの Install Operator ページを使用してこの情報をインストール時に提供できます。その場合、この情報は、Operator Pod の環境変数として Subscription オブジェクトに伝播されます。

5.10.3.1. Operator が Microsoft Entra Workload ID を使用した CCO ベースのワークフローをサポートできるようにする

Operator 作成者は、Operator Lifecycle Manager (OLM) で実行するプロジェクトを設計する際に、Cloud Credential Operator (CCO) をサポートするようにプロジェクトをカスタマイズすることで、Microsoft Entra Workload ID 対応の OpenShift Container Platform クラスターに対して Operator が認証できるようにすることができます。

この方法では、Operator が CredentialsRequest オブジェクトを作成します。Operator には、オブジェクトを作成するための RBAC 権限と、生成される Secret オブジェクトを読み取るための RBAC 権限が必要です。

注記

デフォルトでは、Operator デプロイメントに関連する Pod は、生成される Secret オブジェクトでサービスアカウントトークンを参照できるように、serviceAccountToken ボリュームをマウントします。

前提条件

  • OpenShift Container Platform 4.14 以降
  • Workload ID モードのクラスター
  • OLM ベースの Operator プロジェクト

手順

  1. Operator プロジェクトの ClusterServiceVersion (CSV) オブジェクトを更新します。

    1. Operator が CredentialsRequests オブジェクトを作成する RBAC 権限を持っていることを確認します。

      例5.24 clusterPermissions リストの例

      # ...
      install:
        spec:
          clusterPermissions:
          - rules:
            - apiGroups:
              - "cloudcredential.openshift.io"
              resources:
              - credentialsrequests
              verbs:
              - create
              - delete
              - get
              - list
              - patch
              - update
              - watch
    2. Workload ID を使用したこの CCO ベースのワークフロー方式のサポートを要求するために、次のアノテーションを追加します。

      # ...
      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 ID トークンパスを認証情報リクエストに追加し、Operator の初期化中に適用します。

      例5.25 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 で調整している他の項目とともに呼び出されます。

      例5.26 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 で認証して、必要な認証情報を受け取ります。

5.10.4. GCP Workload Identity を使用した OLM 管理 Operator 向けの CCO ベースのワークフロー

Google Cloud Platform (GCP) 上で実行されている OpenShift Container Platform クラスターが GCP Workload Identity / Federated Identity モードである場合、そのクラスターは、Google Cloud Platform (GCP) と OpenShift Container Platform の機能を利用して、アプリケーションレベルで GCP Workload Identity の権限を適用しています。

Cloud Credential Operator (CCO) は、クラウドプロバイダー上で実行している OpenShift Container Platform クラスターにデフォルトでインストールされる Cluster Operator です。OpenShift Container Platform 4.17 以降、CCO は GCP Workload Identity を使用した OLM 管理 Operator のワークフローをサポートします。

CCO は GCP Workload Identity のために次の機能を提供します。

  • CCO が GCP Workload Identity 対応のクラスター上で実行されているかどうかを検出する
  • CredentialsRequest オブジェクトをチェックして、Operator に GCP リソースへのアクセスを許可するために必要な情報を提供するフィールドが存在するかどうかを確認する

CCO は、CredentialsRequest オブジェクトの使用を拡張することで、このプロセスを半自動化できます。このオブジェクトにより、GCP Workload Identity ワークフローに必要な情報を含む Secrets の作成を要求できます。

注記

更新の自動承認を使用したサブスクリプションは推奨されません。更新前に権限の変更が必要な場合があるためです。更新の手動承認を使用したサブスクリプションであれば、管理者が新しいバージョンの権限を確認し、必要な手順を実行してから更新できます。

Operator 作成者は、OpenShift Container Platform 4.17 以降の更新された CCO と一緒に使用する Operator を準備する際に、GCP Workload Identity トークン認証への対処 (Operator がまだ未対応の場合) に加えて、ユーザーに指示し、以前の CCO バージョンからの相違を処理するコードを追加する必要があります。推奨される方法は、GCP Workload Identity 関連のフィールドを正しく入力した CredentialsRequest オブジェクトを用意して、CCO に Secret オブジェクトを作成させることです。

重要

バージョン 4.17 より前の OpenShift Container Platform クラスターをサポートする予定がある場合は、CCO ユーティリティー (ccoctl) を使用して GCP Workload Identity 対応情報を含むシークレットを手動で作成する方法をユーザーに提供することを検討してください。以前の CCO バージョンは、クラスター上の GCP Workload Identity モードを認識しないため、シークレットを作成できません。

コードでは、決して表示されないシークレットをチェックし、提供したフォールバック手順に従うようにユーザーに警告する必要があります。

Google Cloud Platform Workload Identity を介して有効期間の短いトークンを使用して GCP で認証するには、Operator によって次の情報を提供する必要があります。

AUDIENCE

AUDIENCE 値は、管理者が GCP Workload Identity を設定するときに GCP で作成し、次の形式で事前にフォーマットした URL である必要があります。

//iam.googleapis.com/projects/<project_number>/locations/global/workloadIdentityPools/<pool_id>/providers/<provider_id>
SERVICE_ACCOUNT_EMAIL

SERVICE_ACCOUNT_EMAIL 値は、Operator 操作中に権限を借用する GCP サービスアカウントのメールアドレスです。次に例を示します。

<service_account_name>@<project_id>.iam.gserviceaccount.com

クラスター管理者は、Web コンソールの Install Operator ページを使用してこの情報をインストール時に提供できます。その場合、この情報は、Operator Pod の環境変数として Subscription オブジェクトに伝播されます。

5.10.4.1. Operator が GCP Workload Identity を使用した CCO ベースのワークフローをサポートできるようにする

Operator 作成者は、Operator Lifecycle Manager (OLM) で実行するプロジェクトを設計する際に、Cloud Credential Operator (CCO) をサポートするようにプロジェクトをカスタマイズすることで、OpenShift Container Platform クラスター上の Google Cloud Platform Workload Identity に対して Operator が認証できるようにすることができます。

この方法では、Operator が CredentialsRequest オブジェクトを作成します。Operator には、オブジェクトを作成するための RBAC 権限と、生成される Secret オブジェクトを読み取るための RBAC 権限が必要です。

注記

デフォルトでは、Operator デプロイメントに関連する Pod は、生成される Secret オブジェクトでサービスアカウントトークンを参照できるように、serviceAccountToken ボリュームをマウントします。

前提条件

  • OpenShift Container Platform 4.17 以降
  • GCP Workload Identity / Federated Identity モードのクラスター
  • OLM ベースの Operator プロジェクト

手順

  1. Operator プロジェクトの ClusterServiceVersion (CSV) オブジェクトを更新します。

    1. Operator が Web ID でロールを引き受けることができるように、CSV 内の Operator デプロイメントに次の volumeMounts および volumes フィールドがあることを確認します。

      例5.27 volumeMounts および volumes フィールドの例

      # ...
            volumeMounts:
      
            - name: bound-sa-token
              mountPath: /var/run/secrets/openshift/serviceaccount
              readOnly: true
            volumes:
               # This service account token can be used to provide identity outside the cluster.
               - name: bound-sa-token
                 projected:
                   sources:
                   - serviceAccountToken:
                     path: token
                     audience: openshift
    2. Operator が CredentialsRequests オブジェクトを作成する RBAC 権限を持っていることを確認します。

      例5.28 clusterPermissions リストの例

      # ...
      install:
        spec:
          clusterPermissions:
          - rules:
            - apiGroups:
              - "cloudcredential.openshift.io"
              resources:
              - credentialsrequests
              verbs:
              - create
              - delete
              - get
              - list
              - patch
              - update
              - watch
    3. GCP Workload Identity を使用したこの CCO ベースのワークフロー方式のサポートを要求するために、次のアノテーションを追加します。

      # ...
      metadata:
       annotations:
         features.operators.openshift.io/token-auth-gcp: "true"
  2. Operator プロジェクトコードを更新します。

    1. サブスクリプション設定によって Pod に設定された環境変数から audienceserviceAccountEmail の値を取得します。

       // Get ENV var
         audience := os.Getenv("AUDIENCE")
         serviceAccountEmail := os.Getenv("SERVICE_ACCOUNT_EMAIL")
         gcpIdentityTokenFile := "/var/run/secrets/openshift/serviceaccount/token"
    2. パッチを適用して適用できる CredentialsRequest オブジェクトがあることを確認してください。

      注記

      CredentialsRequest オブジェクトを Operator バンドルに追加することは現在サポートされていません。

    3. GCP Workload Identity の変数を認証情報リクエストに追加し、Operator の初期化中に適用します。

      例5.29 Operator の初期化中に CredentialsRequest オブジェクトを適用する例

      // apply CredentialsRequest on install
         credReqTemplate.Spec.GCPProviderSpec.Audience = audience
         credReqTemplate.Spec.GCPProviderSpec.ServiceAccountEmail = serviceAccountEmail
         credReqTemplate.CloudTokenPath = gcpIdentityTokenFile
      
      
         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 で調整している他の項目とともに呼び出されます。

      例5.30 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
           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. シークレットから service_account.json フィールドを読み取り、それを使用して GCP クライアントを認証します。

      service_account_json := secret.StringData["service_account.json"]
Red Hat logoGithubRedditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.