BFT名古屋 TECH BLOG

日々の業務で得た知識を所属するエンジニアたちがアウトプットしていきます。

【AWS】VPC内からAPI GatewayのAPIを叩きたい時の話

こんにちは! BFT名古屋支店の佐野です。

今回はAPI Gatewayで作ったAPIVPCの中にあるEC2からアクセスする時のパターンについての、ほんの少しボリューム控えめなお話です。
特にプライベートセグメントから、APIを叩く際の仕組みや注意点などに触れていきます。


はじめに

まずAPI Gatewayで作成できるREST APIには、通常(パブリック)のものと、プライベートタイプのものがあります。

f:id:bftnagoya:20211012203858p:plain
API GatewayAPI

以上の参考画像の通りプライベートタイプのREST APIは、VPC内からのアクセスのみを前提としたもので、例えばEC2からであればAPI Gateway用のVPCエンドポイントを使用してアクセスすることになります。
逆にVPCエンドポイントを介さなければ、たとえVPC内にあるEC2からでもプライベートタイプのREST APIにはアクセスすることはできません。

一方で通常の、パブリックなREST APIは、例えVPC内にあるEC2であっても、インターネットさえ経由できれば問題なくアクセスすることができます。
これは当たり前の話ではありますが、ではインターネットに繋がっていないプライベートなセグメントに置いているEC2からパブリックなREST APIにアクセスしたい場合はどうすればよいのでしょうか?


VPCエンドポイントを経由してパブリックなAPIにアクセスする

特にひっかけもないのですが、VPC内からプライベートタイプのAPIにアクセスする場合と同じように、API Gateway用のVPCエンドポイントを利用することで、プライベートセグメントからパブリックなAPIにアクセスすることができます。

f:id:bftnagoya:20211015204834p:plain
VPCエンドポイントからAPI Gatewayにアクセスする図(APIはインターネット経由のアクセスも受ける)

そうした場合、たとえインターネットゲートウェイやNATゲートウェイによるインターネットへ疎通する経路があったとしても、API GatewayへのアクセスにはVPCエンドポイントを使用した経路が使われるようになります。
ただ、ここからが少し引っかかりポイントです。
もしAPI Gateway用のVPCエンドポイントをデフォルトのままどんどん設定した場合、いざパブリックなAPIにアクセスしようとした時にエラーが出てしまったかと思います。
その原因の多くは、VPCエンドポイントのプライベートDNS名にあります。


プライベートDNS名は無効にする

f:id:bftnagoya:20211012213741p:plain
プライベートDNS名が有効になっている状態(デフォルト)

プライベートDNS名が有効になっている場合、基本的にAPI GatewayエンドポイントからパブリックAPIにアクセスすることができません。
VPCエンドポイントを作成後にパブリックAPIへのアクセスが失敗した場合は、まずはここをチェックするのが良いでしょう。 またAPIにカスタムドメイン名が設定されていて、そのカスタムドメイン名を用いてAPIへのアクセスを行なう場合には、プライベートDNS名が有効になっていても疎通します。

詳しくは以下の公式ドキュメントをご覧ください。

docs.aws.amazon.com


最後に:VPCエンドポイント経由のアクセスと特定IPからのアクセスの両立

以上がVPC内のプライベートセグメントからAPI Gatewayを叩くために必要なリソースと、設定諸々となります。
設定事項と引っかかりポイントさえ分かってしまえば「なんだそんなことだったのか」と思うくらい簡単にできます。

しかし、実はここからまた課題が生まれてきます。
例えば完全にパブリックなAPIに、VPC内のプライベートセグメントからアクセスする場合はここまでの設定で問題なく達成できます。
ですが多くの場合は、APIへアクセスできる接続元を指定し、それ以外の接続元からのアクセスは遮断するという形で構築を行なうこととでしょう。
もしVPC内からVPCエンドポイントを経由したアクセスからのみを許可すればいい場合は、以下のようなリソースポリシーをAPIに設定すれば、VPCエンドポイントを経由していないアクセスは遮断できます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "execute-api:/*"
        },
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "execute-api:Invoke",
            "Condition": {
                "StringNotEquals": {
                    "aws:SourceVpce": "vpce-xxxxxxxxxxxxxxxx"
                }
            }
        }
    ]
}

ですが、このリソースポリシーを用いれば、当然インターネットを経由してくる接続元から一切アクセスすることができなくなります。
例えば、インターネットを経由してくる特定のIPからのアクセスと、VPCエンドポイントを経由してくるVPC内からのアクセス、その両方を許可するにはどうしたらよいか。
今回の内容をさわりとして、以上の内容をまた次回お話しできればと思います。