こんにちは、たーせるです。
本日も AWS Lambda と API Gateway の話をしようと思います。
今回のテーマは「AWS SAM で作った API に対して、簡単なアクセス制限を付けてみよう」という内容で、流れとしては第2話の続き*1という形になります。
お勉強しながらゆっくり進んでいるので、有益なコメントなど大歓迎です。
ちなみにこのシリーズを順に読みたい場合は、Lambda カテゴリからどうぞ。
tercel-tech.hatenablog.com
さて前回は、AWS SAM を利用してサクっと REST API を作ったものの、全世界の端末から実行可能な状態となっていた。
もしも会社や学校でこれをやると、偉い人に注意されてしまうことがある。 たとえ機密情報を扱わない実験的な API であっても、身元の明らかではない端末からアクセスされ得る状態を看過できないというのは、至極尤もな了見でもある*2。
【練習】 API を実行できる IP アドレスを制限しよう
多くの会社では、社内 LAN からインターネットへのアクセスはプロキシサーバを経由する仕掛けが構築されている(と思う)。
そして、自社の情報システム部のネットワーク管理者に問い合わせると、社内 LAN からインターネットへの出口となるグローバル IP アドレスの範囲を教えて貰えるケースがある。
つまり、この IP 帯以外からのアクセスを全て遮断できれば、理論上はある程度素性の明らかな端末からしか API を実行できなくなり、さしあたり最低限の防衛線になるだろう。
template.yaml の修正
以下のように、API の実行を許可する IP 帯をCIDR形式で yaml に指定することで、簡単にアクセス制限を設定できる。
template.yaml
(diff)
Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.8 Events: HelloWorld: Type: Api Properties: Path: /hello Method: get + Auth: + ResourcePolicy: + IpRangeWhitelist: + - mmm.mmm.mmm.mmm/32 + - nnn.nnn.nnn.nnn/32
実際に、template.yaml
にリソースポリシーを追加してデプロイしてみよう。
$ sam deploy
設定した範囲外の IP アドレスから curl
で API のエンドポイント URL を叩くと、想定どおり拒否されることが確認できる。
{"Message":"User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:ap-northeast-1:********██:██████/Prod/GET/hello with an explicit deny"}
一方で、許可された IP アドレスからは普通にアプリケーションコードが実行され、正常系の応答が返ってくる。 おめでとう。
内容としては以上なのだが、この設定によって一体何が起きたかを念の為確認してみよう。
設定の確認
マネジメントコンソールにサインインして、Lambda のトリガになっている API Gateway を確認する。
API Gateway の右隣に表示されているアプリケーション名のリンク(下図赤枠)をクリックすると、API Gateway のマネジメントコンソールに飛べる。
左側のメニューから「リソースポリシー」をクリックすると、自動的に下図の緑枠の設定が追加されていることが確認できる。
これは、指定した IP アドレス範囲以外からの API 実行を拒否するという意味である。
つまりどういうことだって?
template.yaml に書いたたった数行の宣言が、リソースポリシーに化けるんだよ。
Properties: # (略) Auth: ResourcePolicy: IpRangeWhitelist: - nnn.nnn.nnn.nnn/32
これ (↑) が、これ (↓) に自動変換される。
開発のコストパフォーマンスがめちゃくちゃ良い。
{ "Version": "2012-10-17", "Statement": [ (略), { "Effect": "Deny", "Principal": "*", "Action": "execute-api:Invoke", "Resource": "arn:aws:execute-api:ap-northeast-1:████████:████████/Prod/GET/hello", "Condition": { "NotIpAddress": { "aws:SourceIp": "nnn.nnn.nnn.nnn/32" } } } ] }
手作業でこんな長ったらしい JSON を書く気にはならない。
ちなみにこの動画 (↓) の 2:50 あたりから、リソースポリシーを設定するシーンが見られるよ。
リソースポリシーの設定ってそんな面倒なの?
うん。
結局、動画でもポリシージェネレータというチートツールを使ったしね。 少なくとも人間が手書きするには優しくないよね。
設定ミスったら終わるし。
あぁなるほど。
たしかに慣れれば template.yaml を書く方が負荷は低いかもね。