AWS CDK で EIP リソースを明示的に定義しつつ NAT Gateway で使用する構成を実装してみた

AWS CDK で EIP リソースを明示的に定義しつつ NAT Gateway で使用する構成を実装してみた

Clock Icon2025.01.27

こんにちは、製造ビジネステクノロジー部の若槻です。

NAT Gateway をパブリックサブネットに作成すると Elastic IP Address が NAT Gateway に自動的に割り当てられます。これにより VPC 内のリソースからインターネットへのアクセスが可能になり、またその際のパブリック IP アドレスも固定することができます。

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-nat-gateway.html

今回は、AWS CDK で Elastic IP Address のリソースを明示的に定義しつつ NAT Gateway で使用する構成を実装してみました。なお、VPC 内に作成する NAT Gateway は一つのみとします。

やってみた

そもそも Elastic IP Address のリソースを明示的に定義したい理由は以下になります。

  • Elastic IP Address を作成していることを明示的に示したい
  • Elastic IP Address のパブリック IP アドレスを簡単に出力したい

CDK コード

前述の理由を満たす最もシンプルな CDK コードは以下のようになりました。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    // Elastic IP の作成
    const eip = new ec2.CfnEIP(this, 'EIP');

    // VPC の作成
    new ec2.Vpc(this, 'VPC', {
      maxAzs: 2, // 開発環境のため 2 AZ のみ使用
      natGateways: 1, // 開発環境のため NAT Gateway は 1 つのみ作成
      natGatewayProvider: ec2.NatProvider.gateway({
        eipAllocationIds: [eip.attrAllocationId],
      }),
      subnetConfiguration: [
        {
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
      ],
    });

    // Elastic IP アドレスの出力
    new cdk.CfnOutput(this, 'EIPAddress', {
      value: eip.ref,
    });
  }
}

上記をデプロイすると、Elastic IP Address と単一の NAT Gateway が作成されました。

また、Elastic IP Address のパブリック IP アドレスが出力されました。

EC2 のマネジメントコンソールを確認すると、それぞれ CloudFormation で作成された NAT Gateway に Elastic IP Address が割り当てられていることが確認できます。

VPC Construct 単体で NAT Gateway を作成した場合は?

VPC Construct 単体で NAT Gateway を作成した場合にも Elastic IP Address は自動的に作成されて割り当てられますが、Elastic IP Address を出力したい場合に VPC からの EIP リソースの取得が下記のようにあまりスマートにできないのでおすすめできません。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    // VPC の作成
    const vpc = new ec2.Vpc(this, 'VPC', {
      maxAzs: 2, // 開発環境のため 2 AZ のみ使用
      natGateways: 1, // 開発環境のため NAT Gateway は 1 つのみ作成
      subnetConfiguration: [
        {
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
      ],
    });

    // VPC から EIP リソースの取得
    const natGatewayEip = vpc.publicSubnets[0].node.findChild(
      'EIP'
    ) as ec2.CfnEIP;

    // Elastic IP アドレスの出力
    new cdk.CfnOutput(this, 'NatGatewayEip', {
      value: natGatewayEip.attrPublicIp,
    });
  }
}

だめだった方法

はじめ次のような CDK コードで実装しようとしたが、独立して作成された 2 つ目の NAT Gateway の方に Elastic IP Address が割り当てられてしまい、意図通りにいきませんでした。

lib/main-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';

export class MainStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    // VPC の作成
    const vpc = new ec2.Vpc(this, 'VPC', {
      maxAzs: 2, // 開発環境のため 2 AZ のみ使用
      natGateways: 1, // 開発環境のため NAT Gateway は 1 つのみ
      subnetConfiguration: [
        {
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
      ],
    });

    // Elastic IP の作成(NAT Gateway 用)
    const eip = new ec2.CfnEIP(this, 'EIP', {
      domain: 'vpc',
    });

    // 最初のパブリックサブネットを取得
    const publicSubnet = vpc.publicSubnets[0];

    // NAT Gateway の作成(固定 IP を使用)
    const natGateway = new ec2.CfnNatGateway(this, 'NatGateway', {
      subnetId: publicSubnet.subnetId,
      allocationId: eip.attrAllocationId,
    });

    // NAT Gateway の依存関係を設定
    natGateway.addDependency(eip);

    // Elastic IP アドレスの出力
    new cdk.CfnOutput(this, 'EIPAddress', {
      value: eip.ref,
    });
  }
}

おわりに

AWS CDK で EIP リソースを明示的に定義しつつ NAT Gateway で使用する構成を実装してみました。

NAT Gateway に割り当てられた Elastic IP Address を簡単に出力したい場合におすすめの方法なので、ぜひ参考にしてみてください。

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.