猫でもわかるWeb開発・プログラミング

本業エンジニアリングマネージャー。副業Webエンジニア。Web開発のヒントや、副業、日常生活のことを書きます。

AWS CDK では既存の VPC Endpoint に Security Group を追加することはできないようだ

やろうとしたこと

AWS CDK で、 Vpc.fromLookup を使って作成済みの VPC を読み込んできて、そこに Subnet や EC2 インスタンスを追加してアプリケーションを作成しようとした。*1

この VPC では、 CloudWatch Logs のアクセスを VPC Endpoint 経由で行っていた。

あるサービス向けの VPC Endpoint (今回の場合は CloudWatch Logs 向けの VPC Endpoint)は、1つの VPC につき1つしか作成できないので、 既存の VPC Endpoint をそのまま利用する必要があったが、ここでかなりハマってしまった。

VPC Endpoint の仕様について

VPC Endpoint には種類があり、 CloudWatch Logs にアクセスするための VPC Endpoint は、Interface VPC Endpoint というタイプのものである。AWS CDK (TypeScript)だと InterfaceVpcEndpoint という名前のクラスがある(「Interface」 と付いているが、いわゆるオブジェクト指向の Interface ではないので注意)

同じサービス向けの VPC Endpoint は1つのVPCにつき1つしか作成できず、今回利用している VPC にはすでに CloudWatch Logs の VPC Endpoint が作成されているので、これを CDK に読み込んできて利用する必要がある。

Interface VPC Endpoint を利用するには、この VPC Endpoint 用の「ネットワークインターフェース」をサブネットに作成する必要がある。

AWS コンソール上で、VPC エンドポイントの画面を開くと「サブネット」というタブがあり、ここにサブネットを追加することで、ネットワークインターフェースが作成される。

ネットワークインターフェースは、AZ(アベイラビリティゾーン)ごとに1つだけ作成できる。AZ内のどれかのサブネットにインターフェースが作成されていれば、他のサブネットからもいい感じにルーティングされて、CloudWatch Logs アクセスできるようになる。

インタフェースの作成とは別に、セキュリティグループの設定も必要になる。VPC Endpoint にはセキュリティグループが紐付けられていて、これで許可されている IP レンジからのみアクセス可能である。

VPC Endpoint に Security Group を追加しようとした

ここまでで VPC Endpoint を仕様を説明した。

既存の VPC に新しくサブネットを作成し、Interface VPC Endpoint を利用したい場合、気をつけるのは以下の2点。

  • 新しく作成したサブネットがあるAZに、 Interface VPC Endpoint のネットワークインターフェースがあるかどうか確認する
  • VPC Endpoint に設定されているセキュリティグループを確認し、新しく作成したサブネットからのアクセスが許可されているか確認する

今回、ネットワークインターフェースの方は問題なかったが、セキュリティグループは設定が足りていなかったため、設定を追加する必要があった。

この VPC 内では複数のアプリが動いており、複数のアプリが VPC Endpoint を利用していた。アプリごとにセキュリティグループが作成されており、VPC Endpoint には複数のセキュリティグループが紐付けられていた。

そこで、新しく作成するアプリ向けのセキュリティグループを AWS CDK で作成し、それを VPC Endpoint に紐付けようとしたが、これに非常に苦戦した。どうやら、CDK の仕様上、既存の VPC Endpoint にセキュリティグループを追加することはできないようだ(僕が気づいてないだけかもしれないので、知ってる人いたら教えてください...)

新しく作成したサブネットには NAT Gateway も存在しており、 VPC Endpoint が無い状態の場合は NAT Gateway 経由でアクセスできるのだが、 VPC Endpoint がある場合は VPC Endpoint が経由でのアクセスが優先され、セキュリティグループの設定でブロックされてアクセスできない。

どう解決したか

手動でセキュリティグループを作成し、手動で VPC Endpoint に紐づけた。

今回と全く同じケースの場合、取れる対応はこれだけである。そもそも VPC やアプリケーション作成時にもっと考慮しておくべきであった。それについては最後にまとめる。

もう少し詳細に調査してみる

CDK の InterfaceVpcEndpoint について

AWS CDK には InterfaceVpcEndpoint.fromInterfaceVpcEndpointAttributes というものがあり、これを使えばできそうに見える。

const vpcEndpointForCloudWatchLogs = InterfaceVpcEndpoint.fromInterfaceVpcEndpointAttributes(
  this,
  `new-app-log-vpc-endpoint`,
  {
    vpcEndpointId: `vpce-XXXXXXXXXX`,
    port: 443,
  }
);

// 一見このようにセキュリティグループを追加できそうである
vpcEndpointForCloudWatchLogs.connections.addSecurityGroup(securityGroup);

しかし、これではうまく行かない。 fromInterfaceVpcEndpointAttributes の引数に securityGroups というプロパティがあるので、これを使うのかと思ったが、これに何か渡しても何もとくに変化はなかった...

私が使い方を知らないだけなのか?

ちなみに、CDK で VPC Endpoint を作成した場合は、コンストラクタにセキュリティグループを渡せば問題ないっぽい。

ドキュメントを見てもよくわからないし、同じことで困っている人も見かけたが、解決策はなさそうだった

参考 * https://stackoverflow.com/questions/68476496/aws-cdk-add-new-security-group-to-an-existing-vpc-endpoint * https://github.com/aws/aws-cdk/issues/5846

アクセスが Interface VPC Endpoint を経由しているかどうかの確認

CloudWatch Logs にログが送られていなかったので、アクセスできていないのは確かだが、Interface VPC Endpoint を経由しているかどうかで解決策が変わってくる。

Interface VPC Endpoint を経由しているかどうかは、 nslookup や dig コマンドを使えばわかる。

# nslookup や dig がインストールされていない場合はインストールします
apt update
apt install dnsutils

nslookup した結果がローカルIPアドレスになっている場合は Interface VPC Endpoint 経由のアクセスになっている。

$ nslookup logs.ap-northeast-1.amazonaws.com
Server:     172.29.0.2
Address:    172.29.0.2#53

Non-authoritative answer:
Name:   logs.ap-northeast-1.amazonaws.com
Address: 172.29.4.171
Name:   logs.ap-northeast-1.amazonaws.com
Address: 172.29.5.161

そうでない場合

$ nslookup logs.ap-northeast-1.amazonaws.com
Server:     192.168.1.1
Address:    192.168.1.1#53

Non-authoritative answer:
Name:   logs.ap-northeast-1.amazonaws.com
Address: 18.181.204.230
Name:   logs.ap-northeast-1.amazonaws.com
Address: 18.181.204.238
Name:   logs.ap-northeast-1.amazonaws.com
Address: 18.181.204.194
Name:   logs.ap-northeast-1.amazonaws.com
Address: 18.181.204.204
Name:   logs.ap-northeast-1.amazonaws.com
Address: 18.181.204.203
Name:   logs.ap-northeast-1.amazonaws.com
Address: 18.181.204.225
Name:   logs.ap-northeast-1.amazonaws.com
Address: 18.181.204.246
Name:   logs.ap-northeast-1.amazonaws.com
Address: 18.181.204.198

他の解決策

今回は手動でセキュリティグループを作ったが、設定が CDK で管理できなくなるため、基本的にはオススメしない。

例えば、今回 CDK で作成したリソースを削除した場合や変更した場合に、VPC Endpoint やセキュリティグループの対応が漏れて、CloudWatch Logs にアクセスできなくなる、など。

そこで、本来なら以下のような対応をしたほうが望ましい

  • 同一のVPC 内に複数のアプリケーションを共存させるのを避ける
  • VPC からしっかり AWS CDK で作成して管理可能にしておく
    • 基本的には上記2つのどちらかが良いです
  • すでに VPC と VPC Endpoint が作成されてしまっている場合は、VPC Endpoint に付与するセキュリティグループを1つにして、そのセキュリティグループを CDK で読みこんで設定変更するようにする
    • セキュリティグループの紐づけはできないが、すでに紐付けられているセキュリティグループの中身の変更はできると思うので
    • これはどうしようもないときの選択肢

質問などあれば X(twitter)でご連絡ください

www.utakata.work

www.utakata.work

有料部分に追加のコンテンツはありません。役に立ったなと思った方でお金を払ってもいいなと思ったら小銭を投げてもらえると励みになります。

*1:RDSや、その他リソースを共有したいなどの理由で、このような構成を取ることがあるかもしれない

この続きはcodocで購入