サービス アカウント キーを使用して Google Cloud APIs にアクセスする


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

サービス アカウント キーが正しく管理されていないと、セキュリティ リスクが発生します。可能であれば、サービス アカウント キーよりも安全な代替手段を選択してください。サービス アカウント キーで認証する必要がある場合は、秘密鍵のセキュリティや、鍵のローテーションなどの他の管理オペレーションをユーザーが行います。詳細については、サービス アカウント キーを管理するためのベスト プラクティスをご覧ください。

GKE 用 Workload Identity 連携を使用して、GKE から Google Cloud サービスにアクセスすることを強くおすすめします。GKE 用 Workload Identity 連携を使用すると、特定の Google Cloud リソースに対する IAM ロールをクラスタ内のプリンシパル(Kubernetes ServiceAccount など)に付与できます。このプリンシパルは、Security Token Service から有効期間の短い認証情報を使用して、これらの Google Cloud リソースに安全にアクセスできます。

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

目標

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

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

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

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

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

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

GKE 用 Workload Identity 連携を使用する

GKE から Google Cloud サービスへの認証に推奨される方法は、GKE 用 Workload Identity 連携です。GKE 用 Workload Identity 連携を使用すると、Kubernetes ワークロードは、IAM Security Token Service API の有効期間の短い認証情報を使用して、特定の Google Cloud リソースに安全にアクセスできます。

GKE 用 Workload Identity 連携の使用をまず最初に考えてください。このドキュメントは、ユースケースで GKE 用 Workload Identity 連携を使用できない場合にのみ使用してください。

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

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

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

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

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

サービス アカウント キーが正しく管理されていないと、セキュリティ リスクが発生します。可能であれば、サービス アカウント キーよりも安全な代替手段を選択してください。サービス アカウント キーで認証する必要がある場合は、秘密鍵のセキュリティや、鍵のローテーションなどの他の管理オペレーションをユーザーが行います。詳細については、サービス アカウント キーを管理するためのベスト プラクティスをご覧ください。

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

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

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

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

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

料金

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

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

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

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

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

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
cd kubernetes-engine-samples/databases/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 と Cloud Resource Manager API を有効にします。

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

コンテナ クラスタを作成する

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

gcloud container clusters create-auto pubsub-test \
    --region=us-central1

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 を表します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      containers:
      - name: subscriber
        image: us-docker.pkg.dev/google-samples/containers/gke/pubsub-sample:v2

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

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. Google Cloud コンソールで [サービス アカウント] ページに移動します。

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

  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

このコマンドは、Google Cloud コンソールからダウンロードした秘密鍵の内容が格納された 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 環境変数を設定する。

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

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: us-docker.pkg.dev/google-samples/containers/gke/pubsub-sample:v2
        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 \
        --region=us-central1
    

次のステップ