［アップデート］CloudFront VPC origins とは

こんにちは。
AWS re:Invent 2024 には行けない勢なのですが、予選落ち？のアップデート機能がぞくぞく発表されています。

その中から、CloudFront VPC origins について確認してみました。

https://aws.amazon.com/about-aws/whats-new/2024/11/amazon-cloudfront-vpc-origins/

CloudFrontを経由して、プライベートサブネット内のALB、NLB、EC2などのリソース（オリジン）からコンテンツ配信が可能となりました。

これまでCloudFrontを利用する場合は、パブリックサブネットにリソース（オリジン）を配置する必要がありましたが、CloudFront VPC origins を利用することで、最小限の作業で下記が実現できます。

・パブリックIP、パブリックサブネット不要で、プライベートサブネットからインターネットにコンテンツが配信できる
・プライベートサブネット内のリソース（オリジン）へのアクセスは、CloudFront経由のみに制限できる

## これまでの構成
まず、これまでの構成を確認してみます。
CloudFrontからVPCへのアクセスは、IGWを経由して、パブリックサブネットのリソースを経由する必要がありました。パブリックサブネットですので、IGWへのルーティングも必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3928182/290da76f-a8aa-d80c-6e46-ee51321c8790.png)


## CloudFront VPC origins を使うとどうなるのか
VPC originsを作成してみました。作成手順は下記をご確認ください。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-vpc-origins.html

## いきなり結論
・VPC originsを作成すると、CloudFrontマネージドのENIがオリジンのプライベートサブネットに作成される
・ENIにアタッチされる、CloudFrontマネージドのSecurityGroupも合わせて作成される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3928182/9947493a-d949-a5de-a0b7-dc1008ed8d8a.png)


:::note warn
VPC Originsを設定したあと、CloudFrontのオリジン設定で作成したVPC OriginのARNを選択することで利用可能となります。
一方、マネジメントコンソールでは、インターナルなALBやプライベートAPI（APIGW）などもオリジン候補として表示され、設定が可能となっていますが、VPC Originで作成していないプライベートサブネットにあるリソースへは到達性がありません。
例えば、プライベートサブネットのALB自体もオリジンとして設定できますが、到達性のある構成はVPC Originとして作成したALBです。
VPC Origin構成とする場合、オリジンで設定するARNはVPC OriginリソースのARNとする必要がありますので注意しましょう（私はハマりました・・同じ轍を踏まないよう改善要望も出しておりますので今後改善されるかもしれません）
:::

## CloudFront VPC origins の構成
CloudFrontとオリジンは、このCloudFrontが作成したプライベートサブネット内のENIを経由して通信する経路となります。
プライベートサブネットには、このENIが利用するため、少なくとも1つの使用可能なIPアドレスが必要です。プライベートIPとなるため、追加コストはかかりません。
なお、パブリックサブネットは不要となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3928182/58051aba-f706-9b44-e600-103fb1b8cf72.png)


:::note info
VPCにインターネットゲートウェイ（IGW）は必要

プライベートサブネットから直接インターネットに通信することはありませんが、VPCにIGWが不要になるわけではありません。
VPCがインターネットからトラフィックを受信できるようにするため、IGWは必要となります。
なお、IGWはプライベートサブネット内のリソース（オリジン）へのトラフィックのルーティングには使用されないため、IGWへのルーティングを設定する必要はありません。
:::

オリジンとなるALBのSecurityGroupのインバウンドルールでは、CloudFrontマネージドのプレフィックスリストを設定するか、ENIにアタッチされたCloudFrontマネージドのSecurityGroupを設定する必要があります。後者が、より制限されているベストプラクティスとなるでしょう。

また、ENIにアタッチされたCloudFrontマネージドのSecurityGroupのアウトバウンドルールは設定されていません。利用するオリジンのIPやSecurityGroupを指定して、利用者側でアウトバウンドルールを設定する必要がありますので注意しましょう。

## Lambdaはどうなるのか
CloudFront VPC originsでは、オリジンとしてLambdaはサポートされていません。

では、Lambdaをプライベートサブネットに配置してインターネットに公開する構成はどうなるのか、について見ていきます。

Lambdaについては、専用のHTTPエンドポイントとなる、Lambda関数URL（Lambda Function URL）を利用することで、プライベートサブネットのLambdaもインターネットからアクセスさせることができます。

関数URLの形式は次のようになります。

```
https://<url-id>.lambda-url.<region>.on.aws
```

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/urls-configuration.html

このLambda関数URL（Lambda Function URL）はCloudFrontを経由させることも可能であり、CloudFrontの OAC (Origin Access Contorol）を利用することで、関数URLを直接実行させることを制限しつつ、CloudFront経由のアクセスのみ可能なLambdaとすることができます。

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-lambda.html

CloudFront + プライベートサブネットのLambda関数URL構成は次のイメージとなります。

プライベートサブネットのENIはCloudFrontではなく、LambdaのENIとなります。
また、IGWが不要であること、CloudFrontとLambdaが別アカウントであっても利用可能であることが、CloudFront VPC originsとの差異となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3928182/931d404b-8ab1-866b-3400-4025aa1f9ee8.png)

:::note info
Lambda関数URLは、IGWやAPIGWを利用することなく、インターネット経由でLambda関数の実行が可能。

CloudFront + プライベートサブネットのLambda関数URL構成においては、IGWは不要。

また、CloudFrontとLambdaが別アカウントであっても利用可能。
:::


## 最後に
CloudFront VPC Origins を利用することで、パブリックサブネットを作成することなく、CloudFrontを経由したインターネットへのプライベートサブネットからのコンテンツ提供が可能となりました。

サポートされているオリジンはALB、NLB、EC2となりますが、Lambdaについては、既存のLambda関数URLを利用することで、同様の構成をとることができます。

CloudFront VPC Originsについては、本記事の執筆時点ではCloudFrontとオリジンは同一アカウントである必要がありますが、近い将来アカウントを跨いだ利用も可能となるようです。

https://aws.amazon.com/jp/blogs/aws/introducing-amazon-cloudfront-vpc-origins-enhanced-security-and-streamlined-operations-for-your-applications/

他のアップデートも期待して待ちましょう！