mazyu36の日記

某SIer所属のクラウドエンジニアのブログ

【CDK】Connectionsのメソッドを使用して楽に通信設定を行う

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を活用することで、容易に通信許可設定が行えます。

以下に説明が記載されています。

docs.aws.amazon.com

記載されている実装イメージをみると 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を直接定義することは少なくなりそうです。