🕌

AWS CDKでNatGatewayProviderを利用して NAT Instanceを爆速で構築する

2024/03/19に公開

かわごえです。

コスト要件でVPCを極限まで下げたいが、VPC LambdaやVPC CodeBuildを作成したい場合に、NATを作成する必要がある、という悩みにぶつかっていたら、
「VPCにそんなプロパティ生えてたんだ・・・」というものを見つけたので共有です

先に注意事項

  • 今回紹介するNatInstanceProviderは廃止予定です

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.NatInstanceProvider.html

  • またNatInstanceProviderから作成されるインスタンスの元となるAMIはすでにEOLになっています

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_NAT_Instance.html

  • Amazon Linux 2023にユーザーデータでNAT Instanceを構築するNATInstanceProviderV2が導入されているのでそちらを利用しましょう

https://github.com/aws/aws-cdk/pull/29013

  • 基本的にはNAT Gatewayを利用することを推奨です、コスト要件でどうしてもNAT Gatewayの費用(44.64ドル+通信量課金)がミスマッチな場合にNAT Instanceを利用しましょう

ソースコード

import * as cdk from "aws-cdk-lib";
import {
  InstanceClass,
  InstanceSize,
  InstanceType,
  NatInstanceProvider,
  NatTrafficDirection,
  Peer,
  Port,
  Vpc,
} from "aws-cdk-lib/aws-ec2";

const app = new cdk.App();
const stack = new Stack(app, 'Stack')
const provider = NatInstanceProvider.instance({
  instanceType: InstanceType.of(InstanceClass.T2, InstanceSize.MICRO),
  defaultAllowedTraffic: NatTrafficDirection.OUTBOUND_ONLY,
});
const vpc = new Vpc(stack, "TestVPC", {
  natGateways: 1,
  natGatewayProvider: provider,
});
provider.securityGroup.addIngressRule(
  Peer.ipv4(vpc.vpcCidrBlock),
  Port.tcp(443)
);

これだけでした。強い。

コード記載する上での注意点

コードを記載するにあたってはまった点は以下のとおりです。

natGatewaysは0ではなく1以上にする

こちらのプロパティ、名前的には"NAT Gateway"の数をカウントしているような気がしたので最初は0にしたのですが、0にすると1台もインスタンスが立ち上がりませんでした。

どうやらこのnatGatewaysのプロパティは、natGatewayProviderで提供されたプロバイダーから立ち上げるNAT Gatewayの数という意味のようで、0に設定するとNAT GatewayもNAT Instanceも存在しない孤立したプライベートサブネットが誕生します。

natGatewaysは0ではなく1以上に設定をしましょう。

VPC内部にEC2のアクセスを制限する

デフォルトではNAT Instanceに対する通信はインバウンド・アウトバウンドともに全てのポートに対してAnyで解放されています。そのため、SecurityHubからかなりの数の通知がやってまいります。

可能な限りNATにアクセスするCIDRブロックは制御するのがいいかなと。

VPC内に閉じる & HTTPSのみ解放するというのも良いかと思いますし、

provider.securityGroup.addIngressRule(
  Peer.ipv4(vpc.vpcCidrBlock),
  Port.tcp(443)
);

このようにプライベートサブネットのCIDRブロックに制限するのもいいかなと思います。

vpc
  .selectSubnets({ subnetType: SubnetType.PRIVATE_WITH_EGRESS })
  .subnets.map((subnect) => {
    provider.securityGroup.addIngressRule(
      Peer.ipv4(subnect.ipv4CidrBlock),
      Port.tcp(443)
    );
  });

終わりに

冒頭の注意事項でも触れたのですが、NatInstanceProviderは2024.3.19時点で非推奨になっています。

NAT Instanceをどうしても利用したい場合には、ユーザーデータを利用して NAT Instanceを作成するNatInstanceProviderV2を利用しましょう。V1からV2の変更点は、NAT InstanceをAWSが提供しているAMIから作成するか、ユーザーデータから作るかの違いだけなので、NatInstanceProviderからNatInstanceProviderV2に変更をするだけで、移行も進めれるかなと思います!

ただし、あくまでコスト要件でNAT Gatewayがミスマッチだった場合にのみ用途を限定し、マネージドサービスである NAT Gatewayを利用することを改めて推奨したいなと思います。

以上です〜!

Discussion