概要
アプリの開発にGCPを利用しています。
その中で、定期実行させたい処理を、CloudScheduler→AppEngineで行っています。
CloudSchedulerからAppEngineに対してHTTPリクエストを送るのですが、その際にAppEngine側ではCloudSchedulerからのリクエストのみを受け取るようにしました。
実装方法
HTTPリクエストのヘッダを参照して、CloudSchedulerからのリクエストであるかどうかを判定します。
この時、CloudSchedulerからのリクエストであれば、X-Appengine-User-Ip
というヘッダが0.1.0.2
であると言うことを利用します。
- Cloud Taskで、受け取ったHTTPリクエストのヘッダを参照する。
- 1から、Cloud Schedulerが送信したHTTPリクエストであるかを判定する。
- 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
なぜこの方法にしたのか
どうやったらCloudSchedulerからのHTTPリクエストのみを受け付けられるか考えていました。
そこで、Cloud SchedulerからAppEngineに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'
CloudSchedulerのレファレンスにも書かれていますが、これらの特殊なヘッダーはGCP内部用のヘッダーのようです。
今回はこの中から、'X-Appengine-User-Ip': '0.1.0.2'
を利用することにしました。
これについて詳しく調べてみると、GCPのAppEngineファイヤーウォールのガイドにも書いてありました。
GCPのサービスから送られるリクエストは、IPアドレスの範囲が決まっており、CloudSchedulerのジョブによるリクエストは、0.1.2.2/32
とあります。
0.1
で始まるIPアドレスってとても珍しいですよね。