GCP API Gatewayでpushサブスクリプションを認証するためのOpenAPI v2設定ガイド
はじめに
IoTチームの高原です。
GCP上で今回やりたいことは下図です。
Pub/SubのpushサブスクリプションでAPI GatewayにメッセージをHTTPで送信します。
このときpush認証を有効にして、API GatewayでJWT認証をさせます。
API GatewayはOpenAPI v2のドキュメントで設定するため、その手順をご紹介します。
ハマりポイント
最初はAPI Gatewayのサービス間認証を読みながら設定しました。
するとOpenAPI v2には下記を記述するよう書かれています。
securityDefinitions:
DEFINITION_NAME:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "SA_EMAIL_ADDRESS"
x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS"
なのでpushサブスクリプションからサービスアカウントをissuerとしたJWTを受信すると思い込んでいました。
{
"iss": "push-example@project.iam.gserviceaccount.com" // pushサブスクリプションに付与したサービスアカウント
// 他は省略
}
が、実際に上記内容を設定すると、API Gatewayは401を返すばかりで認証はしてくれません。
実際にpushサブスクリプションから受信したJWTをログ出力してデコードしてみると下記のような内容でした。
{
"iss": "https://accounts.google.com",
"email": "push-example@project.iam.gserviceaccount.com" // pushサブスクリプションに付与したサービスアカウント
// 他は省略
}
よく見たらpushサブスクリプションが作成するJWTの内容はここに記載があります。
API GatewayでpushサブスクリプションのJWTを認証させるための試行錯誤がここから始まりました。
設定
下記 2 つのリソースを設定します。
- API Gateway
- Pub/Sub pushサブスクリプション
API Gateway
OpenAPI v2のドキュメントに下記のセキュリティ定義を記述します。
securityDefinitions:
jwt_auth:
type: oauth2
flow: implicit
authorizationUrl: ""
x-google-issuer: https://accounts.google.com
x-google-jwks_uri: https://www.googleapis.com/oauth2/v3/certs
x-google-audiences: https://example-xxxxxxxx.an.gateway.dev/api/v1/example # API GatewayのURL+APIパス
そして、認証対象APIにsecurityスキーマを追記します。
paths:
/api/v1/example:
post:
summary: サンプルAPI
security:
- jwt_auth: []
このドキュメントをAPI Gatewayの構成に適用してデプロイすればAPI Gatewayは設定完了です!
上記設定の理由
認証を有効にしたpushサブスクリプションからは下記のJWT(デコード済)を受信します。
{
"aud": "https://example-xxxxxxxx.an.gateway.dev/api/v1/example", // 指定したpushエンドポイント
"azp": "xxxxxxxxxxxxxxxxxxxxx",
"email": "push-example@project.iam.gserviceaccount.com", // pushサブスクリプションに付与したサービスアカウント
"email_verified": true,
"exp": 1728548339,
"iat": 1728544739,
"iss": "https://accounts.google.com",
"sub": "xxxxxxxxxxxxxxxxxxxxx"
}
"iss"
にissuer(JWTの発行者)が記載されています。
それをOpenAPIドキュメントの"x-google-issuer"
に設定します。
そしてこのJWTの署名検証に使う公開鍵URIを"x-google-jwks_uri"
に設定します。
"aud"
には指定したpushエンドポイントが記載されているので、その値をOpenAPIドキュメントの"x-google-audiences"
に設定します。
Pub/Sub pushサブスクリプション
Pub/Sub用サービスエージェント
iam.serviceAccountTokenCreator
ロールを service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com
に付与します。
この付与によってPub/SubがJWTを作成するために必要なiam.serviceAccounts.getOpenIdToken
権限を得ることができます。
pushサブスクリプションに付与するサービスアカウント
そしてpushサブスクリプション用にサービスアカウントを作成します。
iam.serviceAccounts.actAs
権限が必要なため、ロールroles/iam.serviceAccountUser
を付与してください。
pushサブスクリプション作成
そして今まで設定した項目を元にpushサブスクリプションを作成します。
- pushエンドポイント
- API Gateway+APIパス
- push認証
- 有効に設定
- サービスアカウント
- 上記で作成したもの
上記設定で、無事にpushサブスクリプションからAPI Gatewayの認証が通ります!
今回の学び
公式ドキュメントに書いてあるから、きっとこうなんだ!と決めつけて設定だけいじって試行錯誤する時間が長かったです。
もっと早く実際のJWTをダンプして内容を確認したり、JWTの仕様を理解してAPI Gateway用OpenAPI の拡張を読み込んでいれば問題解決に至るのがもっと早かったと思います。
クラウドの使い方ばかりに習熟するのではなく、もっと基礎的な技術をベースに取り組んだ方がエンジニアとして強くなれると思いました。
Discussion