サービス アカウントを使用した Cloud Platform への認証

このチュートリアルでは、Google Cloud サービス アカウントを作成し、Cloud Platform サービスに対して認証を行うロールを割り当て、GKE 上で稼働するアプリケーションでサービス アカウント認証情報を使用する方法について説明します。

この例では Cloud Pub/Sub を使用しますが、ここで示す手順はどの Cloud Platform サービスにも適用できます。このチュートリアルのサンプル アプリケーションは、サービス アカウントを使用して Cloud Pub/Sub に対する認証を行い、Python ベースのアプリケーションから Pub/Sub トピックにパブリッシュされるメッセージをサブスクライブします。

目標

このチュートリアルでは、次の手順について説明します。

  • サービス アカウントの作成方法
  • Cloud Pub/Sub とやり取りするために必要な役割をサービス アカウントに割り当てる方法
  • アカウントキーを Kubernetes シークレットとして保存する方法
  • サービス アカウントを使用してアプリケーションを構成、デプロイする方法

このチュートリアルで使用するサンプル アプリケーションは、Pub/Sub トピックをサブスクライブし、パブリッシュされたメッセージを標準出力に出力します。アプリケーションに適切な権限を構成した後、gcloud を使用してメッセージをパブリッシュし、コンテナの出力ストリームを調べてメッセージが正しく受信されていることを確認する必要があります。

サービス アカウントによる認証

GKE 内からサービス アカウントを使用して Google Cloud サービスを認証する方法は 3 つあります。

1. Workload Identity を使用する

Workload Identity は、GKE から Google Cloud サービスへ認証する場合におすすめの方法です。Workload Identity を使用すると、Kubernetes リソースを使用して Google Cloud サービス アカウントを構成できます。これがユースケースに当てはまる場合は、最初の選択肢になります。この例は、Workload Identity が適していないユースケースも対象としています。

2. デフォルトの Compute Engine サービス アカウントを使用する

GKE クラスタ内の各ノードは Compute Engine インスタンスです。したがって、デフォルトで GKE クラスタで実行されるアプリケーションは、「Compute Engine のデフォルトのサービス アカウント」を使用して認証を試み、関連付けられたスコープを継承します。

このデフォルトのサービス アカウントには、必要な Google Cloud サービスを使用する権限がある場合とない場合があります。デフォルトのサービス アカウントのスコープを拡張することは可能ですが、セキュリティ リスクが生じる可能性があるためおすすめしません。

3. Secret を使用してサービス アカウントの認証情報を管理する

最後に、アプリケーションのサービス アカウントを作成し、認証キーを Kubernetes secret として挿入します。このチュートリアルでは、これについて主に取り上げます。

サービス アカウントを使用する理由

異なるアプリケーションに対してサービス アカウントをそれぞれ別にする利点は次のとおりです。

  • 特定のアプリケーションが発行した API リクエストを識別しやすくなり、API リクエストの監査が容易になります。

  • 特定のアプリケーションのキーを取り消すことができます。1 つのサービス アカウントを共有していると、すべてのアプリケーションの API アクセスを一度に取り消さなければなりません。

  • セキュリティ インシデントが発生してサービス アカウントの認証情報が危険にさらされた場合に情報漏えいの範囲を小さくすることができます。

始める前に

次の手順で Kubernetes Engine API を有効にします。
  1. Google Cloud Console で Kubernetes Engine ページにアクセスします。
  2. プロジェクトを作成または選択します。
  3. API と関連サービスが有効になるのを待ちます。 これには数分かかることがあります。
  4. Google Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する

このチュートリアルで使用されている以下のコマンドライン ツールをインストールします。

  • gcloud は、Kubernetes Engine クラスタの作成と削除に使用されます。gcloud は、Google Cloud SDK に含まれています。
  • kubectl は、Kubernetes Engine で使用されるクラスタ オーケストレーション システムである Kubernetes の管理に使用されます。gcloud を使用して kubectl をインストールできます。
    gcloud components install kubectl

gcloud コマンドライン ツールのデフォルトの設定

次のようにしてデフォルト値を設定しておくと、gcloud コマンドライン ツールでプロジェクト ID および Compute Engine ゾーン オプションを入力する時間が節約されます。
gcloud config set project project-id
gcloud config set compute/zone compute-zone

API の有効化

このチュートリアルでは、プロジェクトで Pub/Sub API と Resource Manager API を有効にする必要があります。

gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com

コンテナ クラスタの作成

Pub/Sub サブスクライバー アプリケーションをデプロイするクラスタとして、pubsub-test という名前のコンテナ クラスタを作成します。

gcloud container clusters create pubsub-test

ステップ 1: Pub/Sub トピックを作成する

デプロイする Pub/Sub サブスクライバー アプリケーションは、echo という Pub/Sub トピック上の echo-read というサブスクリプションを使用します。アプリケーションをデプロイする前にこれらのリソースを作成します。

まず Pub/Sub トピックを作成します。

gcloud

gcloud pubsub topics create echo

Config Connector

注: この手順には Config Connector が必要です。Config Connector をクラスタにインストールするには、インストール手順を実行してください。

apiVersion: pubsub.cnrm.cloud.google.com/v1beta1
kind: PubSubTopic
metadata:
  name: echo
このマニフェストをデプロイするには、マニフェストを topic.yaml というファイル名でマシンにダウンロードしてから、次のコマンドを実行します。
kubectl apply -f topic.yaml

次に、サブスクリプションを作成します。

gcloud

gcloud pubsub subscriptions create echo-read --topic=echo

Config Connector

apiVersion: pubsub.cnrm.cloud.google.com/v1beta1
kind: PubSubSubscription
metadata:
  name: echo-read
spec:
  topicRef:
    name: echo
このマニフェストをデプロイするには、マニフェストを subscription.yaml というファイル名でマシンにダウンロードしてから、次のコマンドを実行します。
kubectl apply -f subscription.yaml

ステップ 2: Pub/Sub サブスクライバー アプリケーションをデプロイする

次に、Pub/Sub トピックにパブリッシュされたメッセージを受け取るアプリケーション コンテナをデプロイします。このアプリケーションは Python で Google Cloud Pub/Sub クライアント ライブラリを使用して記述されており、GitHub にソースコードが掲載されています。

次のマニフェスト ファイルは、このアプリケーションの Docker イメージの単一インスタンスを実行するデプロイを表します。

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      containers:
      - name: subscriber
        image: gcr.io/google-samples/pubsub-sample:v1

このマニフェストをデプロイするには、マニフェストを pubsub.yaml というファイル名でマシンにダウンロードしてから、次のコマンドを実行します。

kubectl apply -f pubsub.yaml

アプリケーションがデプロイされたら、次のコマンドを実行してポッドを照会します。

kubectl get pods -l app=pubsub
出力:
NAME                      READY     STATUS             RESTARTS   AGE
pubsub-2009462906-1l6bh   0/1       CrashLoopBackOff   1          30s

コンテナの起動が失敗し、ステータスが CrashLoopBackOff になっていることがわかります。次のコマンドを実行して Pod のログを調べます。

kubectl logs -l app=pubsub

出力:

...
google.gax.errors.RetryError: RetryError(Exception occurred in retry method that
was not classified as transient, caused by <_Rendezvous (StatusCode.PERMISSION_DENIED, scopes.) of RPC that terminated with Request had insufficient authentication>)

スタック トレースとエラー メッセージから、アプリケーションに Cloud Pub/Sub サービスを照会する権限がないことがわかります。

ステップ 3: サービス アカウントの認証情報を作成する

GKE で実行されているアプリケーションに Google Cloud Platform サービスへのアクセス権を付与するには、サービス アカウントを使用する必要があります。サービス アカウントを使用すると、アプリケーションに関連付けられた一連の IAM 権限を定義できます。

Console

サービス アカウントを作成するには、Cloud Console でサービス アカウントに移動し、[サービス アカウントを作成] をクリックします。

  1. サービス アカウント名を指定します(pubsub-app など)。
  2. [役割] プルダウンで、[Pub/Sub → サブスクライバー] を選択します。
  3. [キーを作成] をクリックして、キータイプに JSON を選択します。
  4. [作成] をクリックします。

サービス アカウントが作成されると、サービス アカウントの認証情報を含む JSON キーファイルがお使いのパソコンにダウンロードされます。このキーファイルを使用して、Cloud Pub/Sub API への認証を行うようにアプリケーションを構成します。

Config Connector

最初に次のリソースを service-account.yaml としてダウンロードします。

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMServiceAccount
metadata:
  name: pubsub-app
spec:
  displayName: Service account for PubSub example

次のコマンドを実行します。

kubectl apply -f service-account.yaml

次に、サービス アカウントに「Pub/Sub サブスクライバー」の役割を適用します。次のリソースを service-account-policy.yaml としてダウンロードします。[PROJECT_ID] を実際のプロジェクト ID に置き換えます。

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: policy-member-binding
spec:
  member: serviceAccount:pubsub-app@[PROJECT_ID].iam.gserviceaccount.com
  role: roles/pubsub.subscriber
  resourceRef:
    apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
    kind: Project
    external: projects/[PROJECT_ID]

次のコマンドを実行します。

kubectl apply -f service-account-policy.yaml

ステップ 4: 認証情報を Secret としてインポートする

サービス アカウント キーを取得したので、それをコンテナに読み込む方法が必要になります。まず Dockerfile にステップを追加しようとお考えかもしれませんが、サービス アカウント キーはセキュリティ上重要なファイルであるため、コンテナ イメージには保存しないでください。

代わりに、Kubernetes には、ランタイム時に Pod 内のプライベート ファイルを安全にマウントするための Secret リソースタイプが用意されています。

kubectl

JSON キーファイルを pubsub-key という名前のシークレットとして保存するには、ダウンロードされたサービス アカウント認証情報ファイルのパスを指定して次のコマンドを実行します。

kubectl create secret generic pubsub-key --from-file=key.json=PATH-TO-KEY-FILE.json

このコマンドは、Cloud Console からダウンロードした秘密鍵の内容が格納された key.json ファイルを含む pubsub-key というシークレットを作成します。シークレットを作成したら、キーファイルをパソコンから削除してください。

Config Connector

次のリソースを service-account-key.yaml としてダウンロードします。

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMServiceAccountKey
metadata:
  name: pubsub-key
spec:
  publicKeyType: TYPE_X509_PEM_FILE
  keyAlgorithm: KEY_ALG_RSA_2048
  privateKeyType: TYPE_GOOGLE_CREDENTIALS_FILE
  serviceAccountRef:
    name: pubsub-app

次のコマンドを実行します。

kubectl apply -f service-account-key.yaml

ステップ 5: アプリケーションにシークレットを構成する

pubsub-key シークレットをアプリケーションで使用するには、デプロイの仕様を次のように変更する必要があります。

  1. シークレットを含むボリュームを定義する。
  2. シークレット ボリュームをアプリケーション コンテナにマウントする。
  3. シークレット ボリューム マウント内のキーファイルを指す GOOGLE_APPLICATION_CREDENTIALS 環境変数を設定する。

更新されたマニフェスト ファイルは次のようになります。

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      volumes:
      - name: google-cloud-key
        secret:
          secretName: pubsub-key
      containers:
      - name: subscriber
        image: gcr.io/google-samples/pubsub-sample:v1
        volumeMounts:
        - name: google-cloud-key
          mountPath: /var/secrets/google
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /var/secrets/google/key.json

このマニフェスト ファイルは、認証情報をアプリケーションで使用可能にする目的で、次のものを定義します。

  • pubsub-key というシークレットを使用する google-cloud-key というボリューム。

  • コンテナ内の /var/secrets/google ディレクトリで google-cloud-key にアクセスできるようにするボリューム マウント

  • 値として /var/secrets/google/key.json が設定された GOOGLE_APPLICATION_CREDENTIALS 環境変数。この環境変数には、シークレットがボリュームとしてコンテナにマウントされているときに認証情報ファイルが格納されます。

GOOGLE_APPLICATION_CREDENTIALS 環境変数は、Google Cloud クライアント ライブラリ(この例では Python 用の Cloud Pub/Sub クライアント)によって自動的に認識されます。

このマニフェストをデプロイするには、マニフェストを pubsub-with-secret.yaml というファイル名でマシンにダウンロードしてから、次のコマンドを実行します。

kubectl apply -f pubsub-with-secret.yaml

マニフェストが正しくデプロイされると、ポッドのステータスが Running になります。

kubectl get pods -l app=pubsub
出力:
NAME                     READY     STATUS    RESTARTS   AGE
pubsub-652482369-2d6h2   1/1       Running   0          29m

ステップ 6: Pub/Sub メッセージの受信をテストする

これでアプリケーションの構成が完了したので、次のようにして echo という Pub/Sub トピックにメッセージをパブリッシュします。

gcloud pubsub topics publish echo --message="Hello, world!"

数秒以内にメッセージがアプリケーションによってピックアップされ、出力ストリームに出力されます。デプロイされているポッドのログを調べるには、次のコマンドを実行します。

kubectl logs -l app=pubsub
出力:
Pulling messages from Pub/Sub subscription...
[2017-06-19 12:31:42.501123] ID=130941112144812 Data=Hello, world!

これで、サービス アカウントの認証情報を使用して Pub/Sub API に対して認証を行うように GKE 上のアプリケーションを正常に構成しました。

クリーンアップ

このチュートリアルで使用するリソースについて、Google Cloud Platform アカウントに課金されないようにする手順は次のとおりです。

  1. Pub/Sub サブスクリプションとトピックをクリーンアップします。

    gcloud pubsub subscriptions delete echo-read
    gcloud pubsub topics delete echo
  2. コンテナ クラスタを削除します。

    gcloud container clusters delete pubsub-test

次のステップ