CDKでセキュリティグループからの通信のみを許可するインバウンドルールを作成する

# やりたいこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/fca91282-4422-26f4-3807-8eedb4e84dc9.png)
- CDK(v2)で、インターフェース型のエンドポイントを作成する。
    - 今回はGlueのエンドポイントだが、インターフェース型なら何でもOK
- そのエンドポイントのセキュリティグループに、別のセキュリティグループからのアクセス許可のみを与える。
- その際、IPでのアクセス許可は実施しない。

ポイントは、「別のセキュリティグループからのアクセス許可**のみ**を与える」という部分です。IPでの許可は与えません。
少しハマったのでやり方を共有します。

## 前提条件
- CDK 2.62.2
    - これ以外のバージョンでも使える話だと思いますが、詳細はドキュメントの確認をお願いいたします。
- 言語はTypeScript

# 間違った方法
以下のようなCDKのコードを書きました（EC2インスタンスなどの部分は省略して、今回の説明に必要な部分だけ記載しています）。

```typescript
    // VPCなど
    const vpc : ec2.Vpc = new ec2.Vpc(this, "cdk-vpc", {
      ipAddresses: ec2.IpAddresses.cidr("10.0.0.0/16"),
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: "public-",
          subnetType: ec2.SubnetType.PUBLIC
        },
        {
          cidrMask: 24,
          name: "private-",
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS
        }
      ]
    });
    
    
    // EC2用のセキュリティグループ
    const ec2SecurityGroup = new ec2.SecurityGroup(
      this,
      "Ec2SecurityGroup",
      {
        securityGroupName: "Ec2SecurityGroup",
        vpc: vpc
      }
    );

    // InterfaceEndpoint用のセキュリティグループ
    const interfaceEndpointSecurityGroup = new ec2.SecurityGroup(
      this,
      "InterfaceEndpointSecurityGroup",
      {
        securityGroupName: "InterfaceEndpointSecurityGroup",
        vpc: vpc
      }
    );

    // EC2用のセキュリティグループからの通信を許可
    interfaceEndpointSecurityGroup.addIngressRule(
      ec2.Peer.securityGroupId(ec2SecurityGroup.securityGroupId),
      ec2.Port.tcp(443)
    );


    // Glue VPCE
    vpc.addInterfaceEndpoint("GLUEInterfaceEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.GLUE,
      subnets: {
        subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS
      },
      securityGroups: [interfaceEndpointSecurityGroup],
    });
```

この記載だと、作成されたインターフェース用のセキュリティグループのインバウンドルールは以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/6e2b1951-0fc7-e8ad-74c2-e55d5bf0fb90.png)

1行目は、自身で追加しているEC2用のセキュリティグループに対する許可ですが、2行目は**IPアドレスによる許可が勝手に追加**されています。

## 原因
インターフェース型のVPCエンドポイントを作成する、`InterfaceVpcEndpoint`で指定するパラメータに問題がありました。
[こちらのドキュメント](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ec2.InterfaceVpcEndpoint.html#open:~:text=this%20to%20work.-,open%3F,-Type%3A%20boolean)を見ると、`InterfaceVpcEndpoint`は`open`という任意のパラメータを持ちます。

>open?
>Type: boolean (optional, default: true)
>
>Whether to automatically allow VPC traffic to the endpoint.
>
>If enabled, all traffic to the endpoint from within the VPC will be automatically allowed. This is done based on the VPC's CIDR range.

記載の通り、このパラメータを有効にすると、**VPC内からのエンドポイントへのトラフィックが自動的に許可**されます。
具体的な挙動で言うと、セキュリティグループのインバウンドルールにVPCのCIDRからの許可ルールが追加されるようです。
そして、このパラメータは**デフォルトで有効**となっています。今回は何も指定していないため、デフォルトで`open`が有効となり、勝手にインバウンドルールにIPでのアクセス許可が追加されてしまいました。

# 正しい方法
`addInterfaceEndpoint`のパラメータである`open`を明示的に`false`に指定してあげます。

```typescript
    // Glue VPCE
    vpc.addInterfaceEndpoint("GLUEInterfaceEndpoint", {
      service: ec2.InterfaceVpcEndpointAwsService.GLUE,
      subnets: {
        subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS
      },
      securityGroups: [interfaceEndpointSecurityGroup],
      open: false
    });
```
そうすると、今度は意図したセキュリティグループからの通信の許可のみのルールとなりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2949357/6b4e473b-9b80-bd23-169e-6181b86c91c9.png)

# おわりに
CDKはL2の抽象度で記載すると、色々と良い感じにしてくれて楽になる一方で、一部融通が利かなくなる時がありますね。
今回はパラメータの変更で済みましたが、これを毎回探すのがなかなか大変そうです。
ただ、そういう試行錯誤も含めて、CDK書いていて楽しいですね。これはハマる人が多いのも頷けます。
もちろんCloudFormationもサクッとIaCを試すのに便利ですが、ガッツリIaC使った開発PJを進めるのなら、CDKおすすめです。