GoogleAppEngineでCloud SchedulerからのHTTPリクエストのみを受け付ける

こんにちは、ピリカの開発の冨田です。

ピリカのごみ拾いSNS「ピリカ」は、Google Cloud Platformを利用しています。

その中で、定期実行させたい処理を、Cloud Scheduler→AppEngineで行っています。

Cloud SchedulerからApp Engineに対してHTTPリクエストを送るのですが、その際にApp Engine側ではCloud Schedulerからのリクエストのみを受け取るようにしました。

f:id:kahi0223:20211203122844p:plain
Cloud SchedulerからApp EngineにHTTPリクエストを送る

実装方法

HTTPリクエストのヘッダを参照して、Cloud Schedulerからのリクエストであるかどうかを判定します。

この時、Cloud Schedulerからのリクエストであれば、X-Appengine-User-Ipというヘッダが0.1.0.2であると言うことを利用します。

  1. Cloud Taskで、受け取ったHTTPリクエストのヘッダを参照する。
  2. 1から、Cloud Schedulerが送信したHTTPリクエストであるかを判定する。
  3. 2が真であった時のみ、処理を実行する。
from flask import Request
from flask import request

def check_request(request: Request) -> bool:
"""リクエストがGoogleCloudSchedulerからのものであるかを確認する
'"""
gae_ip = request.headers.get("X-Appengine-User-Ip")
if not gae_ip or not gae_ip.startswith("0.1.0.2"):
     return False
else:
    return True

なぜこの方法にしたのか

どうやったらCloud SchedulerからのHTTPリクエストのみを受け付けられるか考えていました。

そこで、Cloud SchedulerからApp EngineにHTTPリクエストを送信したときのヘッダーを調べてみることにしました。

ヘッダーを出力してみたところ、下記のようにX-Appengine-**X-CloudScheduler-**といったヘッダーが付与されています。

'Host': 'XXX', 
'X-Forwarded-For': '0.1.0.2, 169.254.1.1', 
'X-Forwarded-Proto': 'http', 
'Forwarded': 'for="0.1.0.2";proto=http', 
'Content-Length': '0', 
'User-Agent': 'AppEngine-Google; (+http://code.google.com/appengine)', 
'X-Cloudscheduler': 'true', 
'X-Cloudscheduler-Jobname': 'XXX', 
'X-Appengine-Country': 'ZZ', 
'X-Cloud-Trace-Context': 'XXX1', 
'Traceparent': 'XXX', 
'X-Appengine-Timeout-Ms': '599998', 
'X-Appengine-Https': 'off', 
'X-Appengine-User-Ip': 'XXX', 
'X-Google-Internal-Skipadmincheck': 'true', 
'X-Appengine-Request-Log-Id': 'XXX', 
'X-Appengine-Default-Version-Hostname': 'XXX'

( HTTPリクエスト抜粋)

Cloud Schedulerのレファレンスにも書かれていますが、これらの特殊なヘッダーはGCP内部用のヘッダーのようです。

今回はこの中から、'X-Appengine-User-Ip': '0.1.0.2'を利用することにしました。

これについて詳しく調べてみると、GCPのApp Engineファイヤーウォールのガイドにも書いてありました。

GCPのサービスから送られるリクエストは、IPアドレスの範囲が決まっており、Cloud Schedulerのジョブによるリクエストは、0.1.2.2/32とあります。

0.1で始まるIPアドレスってとても珍しいですよね。