AWS CDK で CloudFront+VPCオリジン+プライベートALBを一撃で構築する(TypeScriptコード付き)
Contents
概要
これまでは、CloudFront から ALB に接続する際には、パブリックサブネットに ALB を配置していました。昨年、 CloudFront に「VPC オリジン」という機能を追加しました。 この機能により、ALB をプライベートサブネットに配置してあっても CloudFront と接続できるようになります。これによって、セキュリティ強化、パブリック IP アドレスの管理コスト削減、アーキテクチャの簡素化などのメリットが得られます。
詳細は以下を参照してください。
参考:AWS ブログ>Amazon CloudFront VPC オリジンの紹介: アプリケーションのセキュリティ強化と運用の合理化
今回は、VPC オリジンを AWS CDK を使って構築します。
参考:CloudFront VPC origins とは
CloudFront のオリジンとして VPC のプライベートサブネットに配置した、EC2/ALB/NLB に直接接続できる機能です。具体的には、CloudFront からインターネットゲートウェイ(IGW)を通して、プライベートサブネット内に作成されたネットワークインターフェース(ENI)と通信することで実現しています。
前提条件は次の通りです。
- VPC は CloudFront ディストリビューションと同じ AWS アカウントに存在すること
- VPC にはインターネットゲートウェイがアタッチされていること
- プライベートサブネットには、少なくとも1つの利用可能な IPv4 が存在すること
参考:CloudFront 開発者ガイド>Restrict access to an AWS origin
構築する全体像
- 今回は検証のため、ALB は単独で固定レスポンスを返すように構築
- ALB のセキュリティグループでは「com.amazonaws.global.cloudfront.origin-facing」を Inbound で許可
VPC オリジン機能提供前の構成はこのようになります。
実装
package.json
2025 年 2 月より、AWS CDK CLI(aws-cdk)と CDK コンストラクトライブラリ(aws-cdk-lib)は同時リリースではなくなり、AWS CDK CLI は 2.1000.0
のようなバージョンになりました。
参考:AWS ブログ>AWS CDK は AWS CDK CLI と CDK コンストラクトライブラリを分離します
CDK を実行しているとコンソールにこのような表示がされています。
Overview: Starting in CDK 2.179.0, CLI versions will no longer be in
lockstep with CDK library versions. CLI versions will now be
released as 2.1000.0 and continue with 2.1001.0, etc.
よって、今まで同じバージョンを指定していたのを修正する必要があります。具体的には以下のようなバージョン指定になります。
"devDependencies": {
"aws-cdk": "^2.1000.0",
:
},
"dependencies": {
"aws-cdk-lib": "^2.180.0",
:
}
CDK のコード
1. VPC 作成
ALB 配置用の VPC を作成します。今回は検証ですので必要最低限となっています。
// Create VPC
const vpc = new ec2.Vpc(this, 'VPC', {
maxAzs: 2,
natGateways: 0,
// subnet
subnetConfiguration: [
{
cidrMask: 24,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC
},
{
cidrMask: 24,
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS
}
]
})
2. ALB の作成
続いて、プライベートサブネットに配置する ALB とセキュリティグループを作成します。セキュリティグループでは、指定したマネージドプレフィックスリストからの Inbound を許可します。
CloudFront のマネージドプレフィックスリスト名は「com.amazonaws.global.cloudfront.origin-facing」なのでマネジメントコンソールで ID を調べます。
// create SecurityGroup for ALB
const albSg = new ec2.SecurityGroup(this, 'ALBSecurityGroup', {
vpc: vpc,
description: 'ALB Security Group'
})
// CloudFrontからのみアクセスを許可するために、
// CloudFrontのマネージドプレフィックスリストを使用
albSg.addIngressRule(
ec2.Peer.prefixList(props.prefixList), // ここでは"pl-58a04531"のような値を指定
ec2.Port.tcp(80),
'Allow ALB from CloudFront managed prefix list only'
)
// create ALB on Private Subnet
const alb = new elbv2.ApplicationLoadBalancer(this, 'ALB', {
vpc: vpc,
internetFacing: false,
vpcSubnets: {
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS
},
securityGroup: albSg
})
3. リスナー追加
今回は検証のため HTTP アクセスとします。
// add Listener
const listener = alb.addListener('Listener', {
port: 80,
open: false,
defaultAction: elbv2.ListenerAction.fixedResponse(200, {
contentType: 'text/plain',
messageBody: 'CloudFront with VPC Origin and ALB'
})
})
4. CloudFront ディストリビューションの作成
CloudFront ディストリビューションを作成します。デフォルトビヘイビアに VPC オリジンを指定し、ALB を紐づけます。
// Create CloudFront Distribution
const cloudfront = new cloudFront.Distribution(this, 'CloudFrontVpvOrigin', {
comment: 'CloudFront with VPC Origin and ALB',
// TLS v1.2 2021を使用してセキュリティを強化
minimumProtocolVersion: cloudFront.SecurityPolicyProtocol.TLS_V1_2_2021,
enableIpv6: false,
defaultBehavior: {
// VPCオリジンを作成し、プライベートサブネットのALBと接続
origin: origins.VpcOrigin.withApplicationLoadBalancer(alb, {})
// キャッシュ設定などその他の挙動も設定可能
//originRequestPolicy: cloudFront.OriginRequestPolicy.ALL_VIEWER,
//cachePolicy: cloudFront.CachePolicy.CACHING_OPTIMIZED,
//allowedMethods: cloudFront.AllowedMethods.ALLOW_GET_HEAD,
}
})
デプロイ&動作確認
cdk deploy
をして、ブラウザから http://hogehoge.cloudfront.net
にアクセスし、動作確認を行ないます。
無事に ALB のカスタムレスポンスが表示されました!
※ 動作確認したあとは、忘れないように cdk destroy
をしておきましょう!
CDK destroy でのエラー対処法
CDK でスタックを削除する際に、次のようなエラーメッセージが表示される場合があります。
CloudfrontVpcOriginAlbStack | 18 | 21:30:35 | DELETE_FAILED |
AWS::IAM::Role | Custom::VpcRestrictDefaultSGCustomResourceProvider/Role
(CustomVpcRestrictDefaultSGCustomResourceProviderRole26592FE0)
Resource handler returned message: "Cannot invoke "String.contains(java.lang.CharSequence)"
because "errorMsg" is null"
(RequestToken: 19658980-75ef-b65b-6227-f49cf8a4ac28, HandlerErrorCode: InternalFailure)
18 Currently in progress: CloudFrontVpvOriginD4703B39
CloudFormation のテンプレートを見ると、以下のカスタムリソースに使用している IAM ロールのようです。 Lambda の Description を見ると、VPC のデフォルトセキュリティグループを制限するためのカスタムリソースプロバイダーに関連する IAM ロールの削除に失敗している状態です。
"Runtime": "nodejs20.x",
"Description": "Lambda function for removing all inbound/outbound rules from the VPC default security group"
対応方法
今回は、「1.」の方法を使うことで無事にスタック削除ができました。
-
強制削除オプションを使用する
cdk destroy --force
-
依存リソースを手動で削除する
- AWS Management Console にログイン
- CloudFormation コンソールでスタックのリソースを確認
- 関連する Lambda 関数と IAM ロールを手動で削除
- その後、再度 cdk destroy を実行
-
CloudFormation スタックを直接削除する
- CloudFormation コンソールから該当するスタックを選択し、「削除」を実行
- 「スタックの削除に失敗したリソースを保持する」オプションを無効化して削除を試みる
このエラーは CDK が作成したリソースの削除時にのみ発生し、構築自体やアプリケーションの動作には影響しません。主に Lambda カスタムリソースの内部処理におけるエラーに起因しています。なお、このエラーは CDK のバージョンによって発生パターンが異なる場合があります。最新の CDK バージョンを使用することで解決する場合もあります。
まとめ
今回は、AWS CDK で CloudFront の VPC オリジンを作成できることを検証しました。この検証環境では最小限の構成としていますが、本番環境で活用する際には以下の点も考慮すると良いでしょう:
- HTTPS 対応:ALB と CloudFront 間の通信、およびエンドユーザーからのアクセスを暗号化するための ACM 証明書の導入
- セキュリティ強化:AWS WAF との連携による Web アプリケーションの保護
- ログとモニタリング:CloudFront のログ出力や、CloudWatch メトリクスやアラームの設定
- キャッシュ戦略:CloudFront のキャッシュポリシー最適化によるパフォーマンス向上
以上
Discussion