Prefix Listを作成し2つのAWSアカウントで共有する

## 概要
先日VPCでPrefix Listが利用できるようになりました！

どういうものかというと

- Cidrブロックをリストとしてまとめておく
    - VPCセキュリティグループとルートテーブルの設定に利用可能
    - アカウント間でも共有も可能

というものです。

セキュリティグループにIPアドレスをたくさん書かなくてよくなり、
環境が複数あっても共通で使うものはどれか１つのアカウントで管理されていればそれを使える、という世界が実現できそうだったので試してみました。

▼リリース記事はこちら
[Amazon Virtual Private Cloud (VPC) customers can now use their own Prefix Lists to simplify the configuration of security groups and route tables](https://aws.amazon.com/about-aws/whats-new/2020/06/amazon-virtual-private-cloud-customers-use-prefix-lists-simplify-configuration-security-groups-route-tables/?nc1=h_ls)

## 今回確認したいこと
- 共有する場合に必要な手順、共有先での見え方
- Prefix Listを複数アカウント間で共有した時にちゃんと機能するか

## 検証
手順は以下の流れで行うこととします。

- 自宅のIPアドレスを設定したPrefix Listを作成
- 作成したPrefix Listを別のAWSアカウントに共有する
- EC2に設定したセキュリティグループのIngressで作成したPrefix Listからのsshのみ許可する
  - 【共有元】AWSアカウント Hoge: EC2-hoge
  - 【共有先】AWSアカウント Fuga: EC2-fuga

### STEP1: Prefix Listを作成する
マネジメントコンソール、CLI、CloudFormationでの作成が可能です。

▼マネジメントコンソールから作成する場合
以下のようにプレフィックスリスト名や最大エントリ数、エントリ(CidrBlock)を指定します。

![スクリーンショット 2020-07-10 午前5.22.33（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413013/5f762ea9-6fae-1c67-5dd9-7658a03a6547.png)

▼CloudFormationで記述した場合

```YAML
  EC2PrefixList:
    Type: 'AWS::EC2::PrefixList'
    Properties:
      AddressFamily: 'IPv4'
      Entries: 
        - Cidr: 'xxx.xxx.xx.xxx/32'
          Description: 'myip'
      MaxEntries: 10
      PrefixListName: 'test-prefix-myip' #[NOTE]Required.Max255文字
      Tags:
        - Key: 'Scope'
          Value: !Sub ${AWS::StackName}
```

### STEP2: 別のAWSアカウントに共有する
作成したPrefix Listの共有にはRAM(AWS Resource Access Manager)を利用することになります。

共有元だけでなく、共有先のAWSアカウントでも作業が必要になるため
ここから先はアカウント別に分けて記述していきます。

#### 【共有元】 AWSアカウントHoge
▼マネジメントコンソールから作成する場合
**自分が共有** > **リソースの共有** からリソースの共有を作成します。
![スクリーンショット 2020-07-10 午前4.10.40（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413013/8dc185da-caf8-67b9-48fc-5d9337a6ebad.png)

上記のように必要事項を入力し、作成すると
共有先AWSアカウントのステータスが**Associating**(共有先アカウントのアクション待ち)になります。
![スクリーンショット 2020-07-10 午前4.19.05（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413013/f41ff7eb-5289-67c5-1ff2-0811c219118a.png)

▼CloudFormationで記述した場合

```YAML
  RAMResourceShare:
    Type: AWS::RAM::ResourceShare
    Properties: 
      AllowExternalPrincipals: true
      Name: 'share-test-prefix-myip'
      Principals: 
        - !Ref AccountIDFuga 
      ResourceArns: 
        - !GetAtt EC2PrefixList.Arn
```

#### 【共有先】 AWSアカウントFuga
こちらの作業はマネジメントコンソールで行います。

リソースの共有先に指定されると、**自分と共有** > **リソースの共有**に招待が来るため
![スクリーンショット 2020-07-10 午前4.28.55（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413013/1e53ee73-840d-50c1-3570-0c63ac5b1118.png)
以下のように承認する必要があります。
![スクリーンショット 2020-07-10 午前4.37.43（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413013/35782c14-3c2e-9efa-faab-5dfc580a8b14.png)


### STEP3: SecurityGroupでPrefix Listを許可する
▼マネージドコンソールから設定する場合
作成したPrefix ListのIDを指定します。
![スクリーンショット 2020-07-10 午前3.36.32（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413013/278eaed9-4fd5-1577-eade-f8d659cc7921.png)

インバウンドルールに指定したPrefix ListのIDが反映されます。
![スクリーンショット 2020-07-10 午前3.43.01（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413013/1e60d208-d29a-c976-e3e6-6c835b5b1595.png)

▼CloudFormationで記述した場合
Propertyに`SourcePrefixListId`を指定することで設定可能でした。

```YAML
  EC2SecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      SecurityGroupIngress:
         - SourcePrefixListId: !Ref EC2PrefixList
           FromPort: 22
           ToPort: 22
           IpProtocol: 'tcp'
      Tags:
        - Key: 'Name'
          Value: !Sub '${AWS::StackName}-ec2'
      VpcId: !Ref EC2VPC
```

### STEP4: 端末からEC2にsshする
どちらのEC2へも作成・設定したPrefix Listを利用して無事接続できました。

▼【共有元】 AWSアカウントHogeのEC2

```
$ ssh -i "hoge_keypair.pem" ec2-hoge-user@ec2-xx-xxx-xxx-xx.ap-northeast-1.compute.amazonaws.com
Last login: Thu Jul  9 19:56:09 2020 from xxxxx

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
```

▼【共有先】 AWSアカウントFugaのEC2

```
$ ssh -i "fuga_keypair.pem" ec2-fuga-user@ec2-xx-xxx-xxx-xx.ap-northeast-1.compute.amazonaws.com
Last login: Thu Jul  9 19:56:09 2020 from xxxxx

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
```

## 最終的なCloudFormationテンプレート
今回行った作業は、共有先での承認作業を除きCloudFormationでの記述が可能でした。
まとめると以下のようになります。

```YAML
AWSTemplateFormatVersion: 2010-09-09
Parameters:
  EC2VPC:
    Type: 'AWS::EC2::VPC::Id'
    Default: ''
  AccountIDFuga:
    Type: 'String'
    Default: ''

Resources:
  #STEP1:PrefixListsを作成する
  EC2PrefixList:
    Type: 'AWS::EC2::PrefixList'
    Properties:
      AddressFamily: 'IPv4'
      Entries: 
        - Cidr: 'xxx.xxx.xx.xxx/32'
          Description: 'myip'
      MaxEntries: 10
      PrefixListName: 'test-prefix-myip' #[NOTE]Required.Max255文字
      Tags:
        - Key: 'Scope'
          Value: !Sub ${AWS::StackName}

  #STEP2:別のアカウントに共有する
  RAMResourceShare:
    Type: 'AWS::RAM::ResourceShare'
    Properties: 
      AllowExternalPrincipals: true
      Name: 'share-test-prefix-myip'
      Principals: 
        - !Ref AccountIDFuga 
      ResourceArns: 
        - !GetAtt EC2PrefixList.Arn

  #STEP3:SecurityGroupでprefix listを許可する
  EC2SecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      SecurityGroupIngress:
         - SourcePrefixListId: !Ref EC2PrefixList
           FromPort: 22
           ToPort: 22
           IpProtocol: 'tcp'
      Tags:
        - Key: 'Name'
          Value: !Sub '${AWS::StackName}-ec2'
      VpcId: !Ref EC2VPC

```

※AWS::RAM::ResourceShareのPrincipalｓにはAWSアカウントID以外に
OrganizationsのOUまたは組織のArnの指定も可能とのこと。
[AWS::RAM::ResourceShare](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ram-resourceshare.html)


## まとめ

- Prefix Listを共有した場合は共有先AWSアカウントでの承認作業が必要
- 共有したPrefix Listでアクセス制限可能
- 共有側でしかPrefix Listの削除、変更(編集)はできない
- 後述の注意点から、別のアカウントに共有する際は最大エントリ数は注意が必要
 
## 利用時の注意点

- セキュリティグループの上限を意識する必要がある
    - 最大エントリ数100で作成したPrefix Listをセキュリティグループに設定しようとした際に、CloudFormationで`The maximum number of rules per security group has been reached. `エラーが発生した
    - 実際にPrefix Listに設定していたエントリはセキュリティグループの上限(デフォルト60)以下だった
        - 最大エントリ数100がそのままセキュリティグループのルール数として認識される
    - 最大エントリ数は後から変更できない


より詳しい上限や制限事項は以下から確認可能です。
[プレフィックスリストの概念とルール](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/managed-prefix-lists.html)
[Amazon VPC のクォータ](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/amazon-vpc-limits.html)


## 参考
[Creating a prefix list](https://docs.aws.amazon.com/vpc/latest/userguide/managed-prefix-lists.html#create-managed-prefix-list)
[AWS::EC2::SecurityGroup Ingress](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group-rule-1.html)