このチュートリアルでは、クライアント側の認証情報ではなく、認証と認可のロジックを処理するプロキシを使用して、モバイルアプリまたはクライアント側アプリから Pub/Sub にメッセージをパブリッシュする方法を説明します。
Identity and Access Management(IAM)を使用して、クライアントから Pub/Sub へのメッセージを認証できますが、このような長期間有効な認証情報は期限切れになりません。クライアント側アプリでは、これらの認証情報はアプリの逆コンパイルやリバース エンジニアリングなどの手法で検出されます。
その代わり、認証と承認のロジックを、次のタスクを行うプロキシにオフロードできます。
- 受信リクエストを認証してユーザーを検証する。
- 適切な IAM 権限とともにリクエストを Pub/Sub に転送する。
このチュートリアルでは、Google Kubernetes Engine(GKE)に Pub/Sub プロキシを実装する方法について説明します。このチュートリアルは、モバイル アプリケーションまたはクライアント側アプリケーション向けの設計を定義して実装する、アプリケーション開発者とシステム設計者を対象としています。Kubernetes の基本的なコンセプトのを理解していることと、Cloud Endpoints に精通していることを前提としています。
このチュートリアルのリクエスト フロー
Pub/Sub がストリーミング パイプラインにどのように適合するかを理解するには、クリックストリーム分析を検討します。このユースケースでは、ユーザーがモバイルアプリをどのように操作しているかを把握できます。こうした分析情報を得るには、ユーザーのアクションをリアルタイムで取得します。次の図は、データの流れを示しています。
アプリによってキャプチャされたデータは、プロキシを経由して Pub/Sub に push されます。Pub/Sub には、有意義な分析を行えるようにデータを集計する Dataflow や Dataproc のような、サブスクライバーのダウンストリームがあります。
次の図は、このチュートリアルで使用するリクエスト フローの詳細を示しています。
次のセクションでは、この図のそれぞれのコンポーネントの相互作用について説明します。
ユーザー認証
モバイルアプリでは、さまざまな方法でユーザーを認証できます。認証フローはアプリに固有のものです。このチュートリアルでは、このようなユーザー認証のソリューションを説明します。このチュートリアルには、このソリューションの実装も伴います。
クライアント アプリから Pub/Sub プロキシへのリクエスト
アプリのバックエンドは、クライアントがローカルに保存する有効期間が短い認証トークンを生成します(たとえば、Android キーストア システムや iOS キーチェーン サービスを使用します)。このチュートリアルでは、OpenID Connect(OIDC)ID トークンを使用してクライアント アプリを認証します。Google は OIDC ID トークンを発行して署名します。
クライアント側のアプリは、OIDC ID トークンを使用して、リクエストを Pub/Sub プロキシに送信します。Pub/Sub プロキシはトークンを検証し、適切な IAM 認証情報とともにリクエストを Pub/Sub に転送します。
メッセージのパブリッシュ
クライアント アプリが正しく認証されたら、Pub/Sub プロキシはパブリッシュ リクエストを Pub/Sub に送信します。Pub/Sub は IAM を使用することで、呼び出し元(Pub/Sub プロキシ)にパブリッシュ リクエストを送信するための適切な権限があることを保証できます。このチュートリアルでは、Pub/Sub プロキシは Compute Engine のデフォルトのサービス アカウントを使用して、Pub/Sub で認証します。Compute Engine のデフォルトのサービス アカウントには編集者 IAM ロール(roles/editor
)があり、これは公開者アクセス権を Pub/Sub プロキシに付与します。
目標
- Pub/Sub プロキシを運用する GKE クラスタを作成する。
- Pub/Sub トピックを作成する。
- Pub/Sub プロキシをデプロイする。
- Pub/Sub プロキシへのリクエストを認証するように Endpoints を構成する。
- メッセージが Pub/Sub にパブリッシュされることを検証する。
費用
このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。
始める前に
-
Google Cloud コンソールでプロジェクトの選択ページに移動します。
-
Google Cloud プロジェクトを選択または作成します。
-
Google Cloud コンソールで、「Cloud Shell をアクティブにする」をクリックします。
Google Cloud コンソールの下部で Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。Cloud Shell はシェル環境です。Google Cloud CLI がすでにインストールされており、現在のプロジェクトの値もすでに設定されています。セッションが初期化されるまで数秒かかることがあります。
- このチュートリアルに必要な環境変数を定義します。
export PROJECT=$(gcloud config get-value project) export REGION=us-central1 export ZONE=${REGION}-b export CLUSTER=pubsub-proxy export TOPIC=proxy-test export SERVICE_ACCOUNT=publish-test export ENDPOINTS_SERVICE="pubtest.endpoints.${PROJECT}.cloud.goog" export GENERATE_TOKEN="https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts"
- Cloud Build、Compute Engine、Google Kubernetes Engine、Artifact Analysis、Container Registry、Endpoints、Service Management、Service Control、Pub/Sub の API を有効にします。
gcloud services enable \ cloudbuild.googleapis.com \ compute.googleapis.com \ container.googleapis.com \ containeranalysis.googleapis.com \ containerregistry.googleapis.com \ endpoints.googleapis.com \ servicemanagement.googleapis.com \ servicecontrol.googleapis.com \ pubsub.googleapis.com
Pub/Sub トピックの作成
Cloud Shell で、メッセージをパブリッシュする Pub/Sub トピックを作成します。
gcloud pubsub topics create $TOPIC
GKE クラスタの作成
Cloud Shell で、GKE クラスタを作成します。
gcloud container clusters create $CLUSTER \ --zone $ZONE \ --scopes "https://www.googleapis.com/auth/cloud-platform"
稼働しているクラスタ用に、認証情報を取得します。
gcloud container clusters get-credentials $CLUSTER \ --zone $ZONE \ --project $PROJECT
コンテナ イメージのビルド
Cloud Shell で、コード リポジトリのクローンを作成します。
git clone https://github.com/GoogleCloudPlatform/solutions-pubsub-proxy-rest
Cloud Build を使用して、ソースからコンテナ イメージをビルドし、Container Registry に保存します。
cd solutions-pubsub-proxy-rest && \ gcloud builds submit --tag gcr.io/$PROJECT/pubsub-proxy:v1
静的外部 IP アドレスの作成
Cloud Shell で、Pub/Sub プロキシ ロードバランサにあとで割り当てるための静的外部 IP アドレスを作成します。
gcloud compute addresses create service-ip --region $REGION
静的 IP アドレスを環境変数
PROXY_IP
に保存します。PROXY_IP=$(gcloud compute addresses describe service-ip \ --region $REGION --format='value(address)')
Endpoints のデプロイ
Pub/Sub プロキシは Endpoints を使用して、ユーザーからのリクエストを認証します。Endpoints は Extensible Service Proxy(ESP)を使用して、認証、モニタリング、トレース、API ライフサイクル管理などの、API 管理機能を提供します。このチュートリアルでは、Endpoints を Pub/Sub プロキシへの受信リクエストの認証のみに使用します。
このチュートリアルでは、Pub/Sub プロキシと一緒に ESP をサイドカーとしてデプロイします。ESP は、受信リクエストを Pub/Sub プロキシに転送する前にインターセプトして認証します。
Cloud Shell で、
[PROJECT_ID]
プレースホルダをopenapi.yaml
ファイル内の Google Cloud プロジェクト ID に置き換えます。sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" openapi.yaml
OpenAPI マニフェスト ファイル内で、
[IP_ADDRESS]
プレースホルダをPROXY_IP
の値に置き換えます。sed -i -e "s/\[IP_ADDRESS\]/$PROXY_IP/g" openapi.yaml
OpenAPI サービス定義を Endpoints にデプロイします。
gcloud endpoints services deploy openapi.yaml
上記のコマンドにより、以下が作成されます。
openapi.yaml
ファイル(pubtest.endpoints.project-id.cloud.goog
)のホスト フィールドで指定した名前を持つマネージド サービス(project-id
は Google Cloud プロジェクトの ID)。- サービス名と、
openapi.yaml
ファイルのx-google-endpoints
拡張機能で定義された Pub/Sub プロキシ ロードバランサの IP アドレス マッピングを使用する DNS の A レコード。
このチュートリアルでは API キーではなく OIDC ID トークンを使用するため、デプロイ中に無視できる警告が表示されます。
WARNING: openapi.yaml: Operation 'post' in path '/publish': Operation does not require an API key; callers may invoke the method without specifying an associated API-consuming project. To enable API key all the SecurityRequirement Objects (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-requirement-object) inside security definition must reference at least one SecurityDefinition of type : 'apiKey'.
サービスが正しくデプロイされているかどうかを確認します。
gcloud endpoints services describe ${ENDPOINTS_SERVICE}
出力は次のようになります。
[...] producerProjectId: project-id serviceConfig: documentation: summary: Pub/Sub proxy exposed as an Endpoint API [...] name: pubtest.endpoints.project-id.cloud.goog title: PubSub Proxy usage: {} serviceName: pubtest.endpoints.project-id.cloud.goog
出力の中で:
project-id
: Google Cloud プロジェクトの ID。
プロキシのデプロイ
Cloud Shell で、プロキシへの HTTPS 接続を許可する自己署名 SSL 証明書を生成します。
openssl req -x509 -nodes -days 365 \ -newkey rsa:2048 -keyout ./nginx.key \ -out ./nginx.crt \ -subj "/CN=${ENDPOINTS_SERVICE}"
SSL 証明書と秘密鍵を使用して Kubernetes Secret を作成します。
kubectl create secret generic nginx-ssl \ --from-file=./nginx.crt \ --from-file=./nginx.key
デプロイ マニフェスト ファイルの
[PROJECT_ID]
プレースホルダを、Google Cloud プロジェクト ID に置き換えます。sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" kube/deployment.yaml
サービス マニフェスト ファイルの
[IP_ADDRESS]
プレースホルダを、PROXY_IP
の値に置き換えます。sed -i -e "s/\[IP_ADDRESS\]/$PROXY_IP/g" kube/service.yaml
プロキシをデプロイします。
kubectl apply -f kube/
デプロイが成功したことを確認します。
kubectl rollout status deployment/pubsub-proxy
出力は次のようになります。
[...] deployment "pubsub-proxy" successfully rolled out
2 つのコンテナ(ESP と Pub/Sub プロキシ)が Pod で稼働していることを確認します。
kubectl get pods $(kubectl get pod \ -l app=pubsub-proxy \ -o jsonpath="{.items[0].metadata.name}") \ -o jsonpath={.spec.containers[*].name}
出力は次のようになります。
esp pubsub-proxy
EXTERNAL-IP
の値が<pending>
から、先に作成した静的外部 IP アドレスに変化することを監視します。kubectl get svc pubsub-proxy -w
出力は次のようになります。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE pubsub-proxy LoadBalancer 10.7.247.212 <pending> 443:31104/TCP 6m32s pubsub-proxy LoadBalancer 10.7.247.212 <PROXY_IP> 443:31104/TCP 6m5s
監視を停止するには、
CTRL+C
を押します。Pub/Sub プロキシが正常にデプロイされると、
https://${ENDPOINTS_SERVICE}/publish
で公開されます。新しい DNS 構成が反映されるまでに数分かかる場合があります。DNS 構成を確認します。
watch nslookup ${ENDPOINTS_SERVICE}
出力は次のようになります。
Server: 169.254.169.254 Address: 169.254.169.254#53 Non-authoritative answer: Name: pubtest.endpoints.project-id.cloud.goog Address: gke-load-balancer-ip
出力の中で:
gke-load-balancer-ip
は、GKE ロードバランサの IP アドレス(プロキシ IP)です。
監視を停止するには、
CTRL+C
を押します。
上記の手順でエラーが発生した場合は、トラブルシューティングをご覧ください。
認証トークンの生成
次の認証トークンの生成手順は、1 つの例として説明しています。本番環境にでは、ユーザーが自身の認証トークンを生成する方法が必要になります。たとえば、Identity-Aware Proxy のドキュメントでは、プログラムで OIDC ID トークンを取得するサンプルコードを探すことができます。
認証トークンを生成するには、次の手順を行います。
OIDC ID トークンを生成する Google Cloud サービス アカウントを作成します。
gcloud iam service-accounts create \ $SERVICE_ACCOUNT \ --display-name $SERVICE_ACCOUNT
サービス アカウントのメール ID を取得します。
SA_EMAIL=${SERVICE_ACCOUNT}@${PROJECT}.iam.gserviceaccount.com
サービス アカウントのサービス アカウント トークン作成者の IAM ロール(
roles/iam.serviceAccountTokenCreator
)を付与します。gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL \ --member user:$(gcloud config get-value account) \ --role roles/iam.serviceAccountTokenCreator
IAM 認証情報 API を使用して OIDC ID トークンを生成します。
TOKEN=$(curl -s ${GENERATE_TOKEN}/${SA_EMAIL}:generateIdToken \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \ -d '{"audience": "'${ENDPOINTS_SERVICE}'", "includeEmail": "true"}' | jq -r ".token")
Endpoints のサービス名は
audience
フィールドで指定されます。audience
クレームは、トークンの受信先を識別します。トークンが正常に作成されたことを確認します。
echo $TOKEN
JSON ウェブトークン(JWT)は次のようになります。
eyJhbGciOiJSUzI1NiIsImtpZCI6IjY4NjQyODlm[...].eyJhdWQiOiJwdWJ0ZXN0LmVuZHBvaW50cy52aXR hbC1vY3RhZ29uLTEwOTYxMi5jbG91ZC5nb[...].SjBI4TZjZAlYo6lFKkrvfAcVUp_AJzFKoSsjNbmD_n[...]
プロキシを使用した Pub/Sub の呼び出し
Cloud Shell で、テスト メッセージをパブリッシュします。
curl -i -k -X POST https://${ENDPOINTS_SERVICE}/publish \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"topic": "'$TOPIC'", "messages": [ {"attributes": {"key1": "value1", "key2" : "value2"}, "data": "test data"}]}'
出力は次のようになります。
HTTP/2 200 server: nginx date: Sun, 02 Jun 2019 03:53:46 GMT ...
メッセージが Pub/Sub トピックに正常にパブリッシュされたかどうかを確認します。
kubectl logs -f --tail=5 deployment/pubsub-proxy -c pubsub-proxy
Pub/Sub プロキシのデプロイログにメッセージ
Successfully published
が表示されます。2019-06-02 03:49:39.723:INFO:oejs.Server:main: Started @2554ms Jun 02, 2019 3:53:44 AM com.google.pubsub.proxy.publish.PublishMessage getPublisher INFO: Creating new publisher for: proxy-test Jun 02, 2019 3:53:47 AM com.google.pubsub.proxy.publish.PublishMessage$1 onSuccess INFO: Successfully published: 569006136173844
トラブルシューティング
Cloud Shell で、Pub/Sub プロキシ Pod 内の両方のコンテナの状態を確認します。
kubectl describe pods $(kubectl get pod -l app=pubsub-proxy \ -o jsonpath="{.items[0].metadata.name}")
ログの出力では、コンテナの状態は
Running
です。[...] Containers: esp: [...] State: Running Started: Fri, 21 Jun 2019 16:41:30 +0530 Ready: True Restart Count: 0 [...] pubsub-proxy: State: Running Started: Fri, 21 Jun 2019 16:41:42 +0530 Ready: True Restart Count: 0 [...]
(省略可)コンテナのログで、他のエラーがないか確認します。たとえば、Pub/Sub プロキシのログを確認するには、次のコマンドを実行します。
kubectl logs -f --tail=10 deployment/pubsub-proxy -c pubsub-proxy
トラブルシューティングについては、次のドキュメントをご覧ください。
クリーンアップ
このチュートリアルで使用したリソースに対して Google Cloud アカウントに課金されないようにするには、このチュートリアル用に作成した Google Cloud プロジェクトを削除するか、このチュートリアルに関連付けられたリソースを削除します。
Google Cloud プロジェクトの削除
課金を停止する最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
リソースを削除する
このチュートリアルで使用した Google Cloud プロジェクトを残しておく場合は、個々のリソースを削除します。
Cloud Shell で、GKE クラスタを削除します。
gcloud container clusters delete $CLUSTER --zone $ZONE --async
ダウンロードしたコード、アーティファクト、その他の依存関係を削除します。
cd .. && rm -rf solutions-pubsub-proxy-rest
Container Registry 内のイメージを削除します。
gcloud container images list-tags \ gcr.io/$PROJECT/pubsub-proxy \ --format 'value(digest)' | \ xargs -I {} gcloud container images delete \ --force-delete-tags --quiet \ gcr.io/${PROJECT}/pubsub-proxy@sha256:{}
Pub/Sub トピックを削除します。
gcloud pubsub topics delete $TOPIC
サービス アカウントを削除します。
gcloud iam service-accounts delete $SA_EMAIL
Endpoints を削除します。
gcloud endpoints services delete ${ENDPOINTS_SERVICE}
静的 IP アドレスを削除します。
gcloud compute addresses delete service-ip --region $REGION
次のステップ
- Endpoints を使用した認証について学習する。
- 長時間実行タスクに Pub/Sub を使用するためのアーキテクチャについて学習する。
- Google Cloud に関するリファレンス アーキテクチャ、図、ベスト プラクティスを確認する。Cloud アーキテクチャ センター をご覧ください。