CDKだとIConnectableインタフェースのプロパティであるconnections
を使うことで通信の許可設定を容易に行えることを最近知りました。
今まではセキュリティグループ(以下SG)を個別に定義し、インバウンドルールを設定ということをやっていましたが、上記の方法にするともっと楽にできそうです。
キャッチアップがてら色々試して整理した結果をまとめます。
目次
今までどうしていたか
ec2.SecurityGroup
を使用してSGを都度生成、また許可ルールも個別に追加していました。
//コンテナのSGを作成 this.bastionSg = new ec2.SecurityGroup(this, 'SecurityGroupContainer', { securityGroupName: 'security-group-container', vpc: props.vpcConstruct.vpc, }) //DBのSGを作成 this.databaseSg = new ec2.SecurityGroup(this, 'SecurityGroupDatabase', { securityGroupName: 'security-group-db', vpc: props.vpcConstruct.vpc, }) //Container->DBのインバウンドルール追加 this.databaseSg.addIngressRule(ec2.Peer.securityGroupId(this.bastionSg.securityGroupId), ec2.Port.tcp(3306))
これでもいいのですが、セキュリティグループの関係を考えながら実装する必要があります。
そのためリソース数やルール数が多いとちょっと辛いです。
IConnectableのconnectionsを使用した通信設定について
IConnectableのプロパティのconnectionsを活用することで、容易に通信許可設定が行えます。
以下に説明が記載されています。
記載されている実装イメージをみると allowFrom
, allowTo
など直感的なメソッドを使用することで通信許可が簡単にできそうです。
なおこちらを使用するためにはIConnectableをImplementしている必要がありますが、L2 Constructが存在するメジャーなサービスは大体カバーされていそうです。
declare const loadBalancer: elbv2.ApplicationLoadBalancer; declare const appFleet: autoscaling.AutoScalingGroup; declare const dbFleet: autoscaling.AutoScalingGroup; // Allow connections from anywhere loadBalancer.connections.allowFromAnyIpv4(ec2.Port.tcp(443), 'Allow inbound HTTPS'); // The same, but an explicit IP address loadBalancer.connections.allowFrom(ec2.Peer.ipv4('1.2.3.4/32'), ec2.Port.tcp(443), 'Allow inbound HTTPS'); // Allow connection between AutoScalingGroups appFleet.connections.allowTo(dbFleet, ec2.Port.tcp(443), 'App can call database');
Connectionsで用意されているメソッドについて
connectionsのメソッドを使用することで通信の許可設定を行えます
用途を確認するために、使用方法を整理してみました。
ケース1:IConnectableリソース間で通信許可を行いたい場合
おそらく一番よく使うユースケースかと思います。
例としてEC2インスタンス -> RDSクラスターの通信許可設定を行いたい場合を考えます。
declare const instance: new ec2.Instance; declare const dbCluster: rds.DatabaseCluster;
以下実装例です。①通信元(EC2)起点での設定と、②通信先(RDS)起点での設定の大きく2つに分かれます。
// ------- ①通信元起点で設定したい場合 --------- // EC2から、RDSのデフォルトポートでRDSへの通信を許可する。 instance.connections.allowToDefaultPort(dbCluster, 'description') // 上記のポート指定バージョン instance.connections.allowTo(dbCluster, ec2.Port.tcp(5432), 'description') // ------- ②通信先起点で設定したい場合 -------- // RDSに対して、RDSのデフォルトポートでEC2からの通信を許可する dbCluster.connections.allowDefaultPortFrom(instance, 'description') // 上記のポート指定バージョン dbCluster.connections.allowFrom(instance, ec2.Port.tcp(5432), 'description')
PostgreSQLの場合デフォルトポートが5432になるのでDefault
がつくメソッドを指定すると、自動的にそのポートで許可設定がされます。
なお1つ目のメソッドallowToDefaultPort
によく似たメソッドとして、allowDefaultPortTo
があります。これは以下のように、通信元 or 通信先どちらのデフォルトポートが採用されるかが異なるので注意が必要です。
※ allowDefaultPortTo
の使い所がいまいち思いつかない…
// (再掲)EC2から、RDSのデフォルトポートでRDSへの通信を許可する。※通信先のデフォルトポートを採用 instance.connections.allowToDefaultPort(dbCluster, 'description') // EC2から、EC2のデフォルトポートでRDSへの通信を許可する。※通信元のデフォルトポートを採用 // なおEC2インスタンスはデフォルトポートが無いのでエラーになります。 instance.connections.allowDefaultPortTo(dbCluster, 'description')
個人的な所感ですが、デフォルトポートだと予期しない値になる可能性もありそうなので、allowTo
, allowFrom
を使うのが良さそうな気がしました。
ケース2:任意の通信先への通信を許可したい場合
以下が実装例です。ポートは範囲で指定する事もできます。
// ポート指定で任意の通信先への通信を許可 instance.connections.allowToAnyIpv4(ec2.Port.tcpRange(10000, 20000), 'description')
ケース3:任意の通信元からの通信を許可したい場合
こちらはデフォルトポートのメソッドも用意されています。
// ポート指定で任意の通信元からの接続を許可 dbCluster.connections.allowFromAnyIpv4(ec2.Port.tcpRange(10000, 20000), 'description') // RDSのデフォルトポートで任意の通信元からの通信を許可 dbCluster.connections.allowDefaultPortFromAnyIpv4('description')
ケース4:自己参照のインバウンドルールを追加
以下が実装例です。ポート指定とデフォルトポートの両方が用意されています。
// ポート指定で自己参照ルールを追加 dbCluster.connections.allowInternally(ec2.Port.tcp(10000), 'description') // RDSのデフォルトポートで自己参照ルールを追加 dbCluster.connections.allowDefaultPortInternally('description')
ケース5:connectionsの管理下にセキュリティグループを追加
addSecurityGroup
は通信の許可設定ではなく、他のSGをオブジェクトの管理下に追加したい場合に使います。
// 追加のSGを定義 const otherSg = new ec2.SecurityGroup(this, 'OtherSG', { securityGroupName: 'other-security-group', vpc: vpc, }) // EC2のconnectionsに追加 instance.connections.addSecurityGroup(otherSg)
終わりに
今後はConnectionsのメソッドを積極的に活用していきたいと思います。SGを直接定義することは少なくなりそうです。