😺

AWS CDK で CloudFront+VPCオリジン+プライベートALBを一撃で構築する(TypeScriptコード付き)

2025/02/25に公開

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

構築する全体像

overview

  • 今回は検証のため、ALB は単独で固定レスポンスを返すように構築
  • ALB のセキュリティグループでは「com.amazonaws.global.cloudfront.origin-facing」を Inbound で許可

VPC オリジン機能提供前の構成はこのようになります。

overview-before

実装

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 のカスタムレスポンスが表示されました!

result

※ 動作確認したあとは、忘れないように 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.」の方法を使うことで無事にスタック削除ができました。

  1. 強制削除オプションを使用する

    cdk destroy --force
    
  2. 依存リソースを手動で削除する

    • AWS Management Console にログイン
    • CloudFormation コンソールでスタックのリソースを確認
    • 関連する Lambda 関数と IAM ロールを手動で削除
    • その後、再度 cdk destroy を実行
  3. CloudFormation スタックを直接削除する

    • CloudFormation コンソールから該当するスタックを選択し、「削除」を実行
    • 「スタックの削除に失敗したリソースを保持する」オプションを無効化して削除を試みる

このエラーは CDK が作成したリソースの削除時にのみ発生し、構築自体やアプリケーションの動作には影響しません。主に Lambda カスタムリソースの内部処理におけるエラーに起因しています。なお、このエラーは CDK のバージョンによって発生パターンが異なる場合があります。最新の CDK バージョンを使用することで解決する場合もあります。

まとめ

今回は、AWS CDK で CloudFront の VPC オリジンを作成できることを検証しました。この検証環境では最小限の構成としていますが、本番環境で活用する際には以下の点も考慮すると良いでしょう:

  • HTTPS 対応:ALB と CloudFront 間の通信、およびエンドユーザーからのアクセスを暗号化するための ACM 証明書の導入
  • セキュリティ強化:AWS WAF との連携による Web アプリケーションの保護
  • ログとモニタリング:CloudFront のログ出力や、CloudWatch メトリクスやアラームの設定
  • キャッシュ戦略:CloudFront のキャッシュポリシー最適化によるパフォーマンス向上

以上

Discussion