📝

API Gateway のリソースポリシーで CloudFront 経由のリクエストをクライアントの IP アドレスで制限できるか

に公開

結論

できました。

  • CloudFront 経由でも API Gateway のリソースポリシーでクライアントの IP アドレスでのアクセス制限は可能
  • API Gateway は CloudFront の c-ip の IP アドレスで判断している可能性がある
  • CloudFront 側で IPv4 と IPv6 のどちらを使用するかで API Gateway のリソースポリシーを変更する必要がある

検証環境

以下の設定で検証環境を構築しました。

  • API Gateway
    • API タイプ: REST API
    • API エンドポイントタイプ: リージョン
    • IP アドレスのタイプ: IPv4
    • リソース: test
    • メソッド: GET
    • 統合タイプ: Mock
    • ステージ名: test
  • CloudFront
    • オリジン: API Gateway のドメイン
    • Origin IP address type: IPv4-only

パターン 1 CloudFront と API Gateway で IPv4 のみを許可

CloudFront ではデフォルトで IPv6 を使用する設定がオンになっているので、本パターンではオフにして IPv4 のみを使用する設定に変更します。

API Gateway のリソースベースポリシーでは以下の通り IPv4 のアドレスを指定します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:012345678901:xxx/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "xx.xx.xx.xx/32"
        }
      }
    }
  ]
}

CloudFront と API Gateway のデプロイ完了後にブラウザから CloudFront 経由でアクセスし、HTTP ステータスコード 200 が返却されることを確認できました。

API Gateway のログには CloudFront-Viewer-Address に IPv4 のアドレスが記録されていました。

一部抜粋
Method request headers:
  CloudFront-Viewer-Address: xx.xx.xx.xx:xx

CloudFront のログには c-ip に IPv4 のアドレスが記録されていました。

一部抜粋
{
    "c-ip": "xx.xx.xx.xx",
    "x-forwarded-for": "-",
}

クライアントから CloudFront に直接アクセスした場合、クライアントの IP アドレスは c-ip に記録されます。
一方で、クライアントからプロキシなどを通して CloudFront にアクセスした場合、c-ip の値はプロキシの IP アドレスになり、クライアントの IP アドレスは x-forwarded-for に記録されます。
標準ログ記録リファレンス - Amazon CloudFront

c-ip
リクエスト元のビューワーの IP アドレス (192.0.2.183 または 2001:0db8:85a3::8a2e:0370:7334 など)。ビューワーが HTTP プロキシまたはロードバランサーを使用してリクエストを送った場合、このフィールドの値はプロキシまたはロードバランサーの IP アドレスです。
...
x-forwarded-for
ビューワーが HTTP プロキシまたはロードバランサーを使用してリクエストを送信した場合、c-ip フィールドの値はプロキシまたはロードバランサーの IP アドレスです。この場合、このフィールドはリクエスト元のビューワーの IP アドレスです。このフィールドには、複数の IP アドレスをカンマで区切って含めることができます。各 IP アドレスは、IPv4 アドレス (192.0.2.183 など) または IPv6 アドレス (2001:0db8:85a3::8a2e:0370:7334 など) にすることができます。

今回はクライアントから CloudFront に直接アクセスしているので、クライアントの IP アドレスは c-ip に記録されています。

パターン 2 CloudFront と API Gateway で IPv6 のみを許可

本パターンでは CloudFront で IPv6 を使用する設定をオンにします。

API Gateway のリソースベースポリシーでは以下の通り IPv6 のアドレスを指定します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:012345678901:xxx/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "xx:xx:xx:xx:xx:xx:xx:xx/128"
        }
      }
    }
  ]
}

CloudFront と API Gateway のデプロイ完了後にブラウザから CloudFront 経由でアクセスし、HTTP ステータスコード 200 が返却されることを確認できました。

API Gateway のログには CloudFront-Viewer-Address に IPv6 のアドレスが記録されていました。

一部抜粋
Method request headers:
  CloudFront-Viewer-Address=xx:xx:xx:xx:xx:xx:xx:xx:xx

CloudFront のログには c-ip に IPv6 のアドレスが記録されていました。

一部抜粋
{
    "c-ip": "xx:xx:xx:xx:xx:xx:xx:xx",
    "x-forwarded-for": "-",
}

パターン 3 CloudFront でのみ IPv6 のみを許可

本パターンでは CloudFront で IPv6 を使用する設定をオンにする一方、API Gateway のリソースポリシーでは IPv4 のアドレスを指定します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:012345678901:xxx/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "xx.xx.xx.xx/32"
        }
      }
    }
  ]
}

API Gateway のデプロイ完了後にブラウザから CloudFront 経由でアクセスしましたが、以下のメッセージとともに HTTP ステータスコードは 403 が返却されました。

{"Message":"User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:ap-northeast-1:********6805:xxx/test/GET/test because no resource-based policy allows the execute-api:Invoke action"}

API Gateway のログには以下のメッセージのみが記録されていました。

一部抜粋
The client is not authorized to perform this operation.

CloudFront のログには c-ip に IPv6 のアドレスが記録されていました。

一部抜粋
{
    "c-ip": "xx:xx:xx:xx:xx:xx:xx:xx",
    "x-forwarded-for": "-",
}

CloudFront には IPv6 でアクセスしているにもかかわらず、API Gateway 側で IPv6 のアドレスが許可されていないことが原因であると思われます。

パターン 4 API Gateway でのみ IPv6 のみを許可

本パターンでは CloudFront で IPv6 を使用する設定をオフにする一方、API Gateway のリソースポリシーでは IPv6 のアドレスを指定します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "execute-api:Invoke",
      "Resource": "arn:aws:execute-api:ap-northeast-1:012345678901:xxx/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "xx:xx:xx:xx:xx:xx:xx:xx/128"
        }
      }
    }
  ]
}

CloudFront と API Gateway のデプロイ完了後にブラウザから CloudFront 経由でアクセスしましたが、以下のメッセージとともに HTTP ステータスコードは 403 が返却されました。

{"Message":"User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:ap-northeast-1:********6805:xxx/test/GET/test because no resource-based policy allows the execute-api:Invoke action"}

API Gateway のログには以下のメッセージのみが記録されていました。

一部抜粋
The client is not authorized to perform this operation.

CloudFront のログには c-ip に IPv4 のアドレスが記録されていました。

一部抜粋
{
    "c-ip": "xx.xx.xx.xx",
    "x-forwarded-for": "-",
}

CloudFront には IPv4 でアクセスしているにもかかわらず、API Gateway 側で IPv4 のアドレスが許可されていないことが原因であると思われます。

まとめ

今回は API Gateway のリソースポリシーで CloudFront 経由のリクエストをクライアントの IP アドレスで制限できるかを試してみました。
どなたかの参考になれば幸いです。

参考資料

Discussion