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

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

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

目標

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

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

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

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

Workload Identity、デフォルトの Compute Engine サービス アカウント、または Secret を使用して、GKE 内からサービス アカウントを使用して Google Cloud サービスに対する認証を行うことができます。

Workload Identity を使用する

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

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

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

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

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

アプリケーションのサービス アカウントを作成し、その認証キーを Kubernetes Secret として挿入できます。このチュートリアルでは、このオプションを中心に説明します。

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

アプリケーションごとに異なるサービス アカウントを使用することには、次の利点があります。

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

  • 特定のアプリケーションのキーを取り消すことができます。1 つのサービス アカウントを共有し、すべてのアプリケーションの API アクセスを同時に取り消す必要はありません。

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

始める前に

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

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

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

GitHub からサンプルコードのクローンを作成します。

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
cd kubernetes-engine-samples/cloud-pubsub/deployment

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

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

Pub/Sub サブスクライバー アプリケーションのデプロイ

次に、アプリケーション コンテナをデプロイして、Pub/Sub トピックにパブリッシュされたメッセージを取得します。このアプリケーションは Python で作成され、Google Cloud Pub/Sub クライアント ライブラリを使用します。ソースコードは GitHub にあります。

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

# 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

このマニフェストをデプロイするには、次のコマンドを実行します。

kubectl apply -f pubsub.yaml

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

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>)

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

サービス アカウントの認証情報を作成する

GKE で稼働するアプリケーションに Google Cloud サービスへのアクセス権を付与するには、サービス アカウントを使用します。サービス アカウントを使用すると、アプリケーションに関連付けられた一連の Identity and Access Management(IAM)権限を定義できます。

Console

サービス アカウントを作成するには:

  1. Cloud Console の [サービス アカウント] に移動します。

    [サービス アカウント] に移動

  2. [サービス アカウントを作成] をクリックします。

  3. [サービス アカウントの詳細] で、サービス アカウント名を入力します(例: pubsub-app)。

  4. オプションで、サービス アカウント ID を変更して説明を追加します。

  5. [作成] をクリックします。

  6. [このサービス アカウントにプロジェクトへのアクセスを許可する] で [ロールを選択] プルダウン リストから [Pub/Sub サブスクライバー] を選択します。

  7. [続行] をクリックしてから、[完了] をクリックしてサービス アカウントを作成します。

  8. サービス アカウントのリストで、作成したサービス アカウントの横にある [操作] > [鍵を管理] の順にクリックします。

  9. [鍵を追加] > [新しい鍵を作成] の順にクリックします。

  10. [キーのタイプ] で、[JSON] を選択します。

  11. [作成] をクリックします。

鍵が作成されると、サービス アカウントの認証情報を含む JSON ファイルがお使いのパソコンにダウンロードされます。この鍵ファイルを使用して、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

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 というシークレットを作成します。Secret を作成したら、コンピュータからキーファイルを削除します。

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

Secret でアプリケーションを構成する

pubsub-key Secret をアプリケーションで使用するには、Deployment の仕様を次のように変更します。

  1. Secret を含むボリュームを定義する。
  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 という Secret を使用する google-cloud-key という Volume。

  • コンテナ内の /var/secrets/google ディレクトリで google-cloud-key を使用できるようにする Volume マウント。

  • 値として /var/secrets/google/key.json が設定された GOOGLE_APPLICATION_CREDENTIALS 環境変数。この環境変数には、Secret を Volume としてコンテナにマウントした後に認証情報ファイルが格納されます。

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

このマニフェストをデプロイするには、次のコマンドを実行します。

kubectl apply -f pubsub-with-secret.yaml

Pod のステータスが Running であることを確認します。

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

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

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

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

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

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 アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

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

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

    gcloud container clusters delete pubsub-test

次のステップ