AWS CDKで既存のSubnetを参照する方法

本記事では、AWS CDKのAmazon EC2 Construct Libraryを利用して、AWS CDKで管理されていないSubnetの参照方法を紹介します。

AWS CDKで管理されていないリソースを、AWS CDKで管理するリソースから参照する場合、fromLookupのようなStaticメソッドをよく使うと思います。本記事では、AWS CDKのAmazon EC2 Construct Libraryを利用して、AWS CDKで管理されていないSubnetの参照方法を紹介します。

環境

  • AWS CDK: 1.56.0
  • TypeScript: 3.9.7

VPCを参照する方法

Subnetを参照するためには、まずVPCを参照する必要があります。VPCの検索パラメータはいくつか用意されていますが、だいたいはvpcIdを使うかと思います。VPCの参照については特に問題ありませんね。

const vpc = ec2.Vpc.fromLookup(this, 'Vpc', {
  vpcId: 'vpc-xxx'
})

Subnetを参照する方法

参照したVPCからSubnetを参照する2つの方法を紹介します。結論としては、「subnetTypeを指定して参照する」がハマるケースであればこちらの方が設定が少なく容易、ハマらなければ「その他の条件を指定して参照する」が良いかと思います。

subnetTypeを指定して参照する

selectSubnetsの検索オプションにsubnetTypeを指定して参照する方法です。この場合はSubnetTypeがPRIVATEのSubetの配列が返されます。

const vpcSubnets = vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE })

SubnetTypeとは、AWS CDKのAmazon EC2 Construct Libraryで定義された、3つのSubnetのパターン(仕様)を示す属性です。AWS CDKでVPCを構築する際は、subnetConfigurationにてsubnetTypeを指定することで、subnetTypeの仕様に合わせたSubnetが作成されます。

SubnetType 仕様
PUBLIC Public IPあり、IGW経由でのインターネットルーティングあり
PRIVATE Public IPなし、NAT-GW経由でのインターネットルーティングあり
ISOLATED Public IPなし、インターネットルーティングなし

一方で、AWS CDKで構築していないVPCからSubnetを参照して利用する場合、SubnetTypeはどのように判定されるのでしょうか。AWS CDKのソースコードから調べてみました。

  1. SubnetのTagに aws-cdk:subnet-type があればその値から判定する(AWS CDKで作成されたSubnetには、このTagが設定されています)
  2. 1で判定できない場合、Subnetの「パブリックIPの自動割り当て」設定が有効の場合はPUBLICと判定する
  3. 2で判定できない場合、Subnetのルートテーブルに「IGWへのルーティングが含まれている」場合はPUBLICと判定する
  4. 3で判定できない場合、PRIVATEと判定する

2~4の判定条件で意図したSubnetが参照できれば「subnetTypeを指定して参照する」方法が利用できます。また、1の判定条件に合致するように既存のSubnetにTag: aws-cdk:subnet-typeを追加しても良いでしょう。

ソースコードはこのあたりにあります。

https://github.com/aws/aws-cdk/blob/v1.56.0/packages/aws-cdk/lib/context-providers/vpcs.ts#L42

// ① Tagsから特定する。cdkで生成されたSubnetにはこのTagが設定されている。
let type = getTag('aws-cdk:subnet-type', subnet.Tags);
// ② MapPublicIpOnLaunch: trueの場合はPublicと判定する
if (type === undefined && subnet.MapPublicIpOnLaunch) { type = SubnetType.Public; }
// ③ ルートテーブルにIgwへのルーティングが含まれている場合はPublicと判定する
if (type === undefined && routeTables.hasRouteToIgw(subnet.SubnetId)) { type = SubnetType.Public; }
// どれにも当てはまらない場合はPrivateと判定する
if (type === undefined) { type = SubnetType.Private; }

※コメントは私が付け加えたものです。

その他の条件を指定して参照する

selectSubnetsの検索オプションにその他の条件を指定して参照する方法です。特定の条件のSubnetを取得する際にもこの方法が利用できます。

以下の例ではsubnetIdを指定して参照しています。

const vpcSubnets = vpc.selectSubnets({
  subnets: [
    ec2.Subnet.fromSubnetAttributes(this, 'subnet-111', {
      subnetId: 'subnet-111', availabilityZone: 'dummy'
    }),
    ec2.Subnet.fromSubnetAttributes(this, 'subnet-222', {
      subnetId: 'subnet-222', availabilityZone: 'dummy'
    }),
  ]
})

※ availabilityZoneは本当は必要ないのですが、現在は指定しないとエラーになるというIssueが上がっています。ワークアラウンドとして適当な文字列を入れておけば回避できるようです。