AWS Resource Access Managerを使用して組織内のアカウントにサブネットを共有する。

# はじめに
[以前](https://qiita.com/sakai00kou/items/7052cc1c574c03a62086)取得した「**AWS Certified Solutions Architect Professional**」の更新時期が近づいてきたため、試験に落ちないようにAWSが提供している無料の試験対策問題やUdemyの模擬試験を解いていたのですが、その中で、`AWS Resource Access Manager`（以下RAM）でサブネットを共有し、他のアカウントから共有されたサブネットを使用してEC2等を作成するような問題がありました。

今までRAMは`Transit Gateway`を共有して使う場合でしか使ったことがなかったため、今回はRAMで共有したサブネットにEC2インスタンスを作成して通信できるか試しつつ、RAMについて勉強してみようと思います。

# AWS Resource Access Managerとは
AWSの様々なリソースを他のアカウント等と共有してそれぞれのアカウントで使用できるようにするための機能です。

AWSのすべてのリソースを共有できるわけではありませんが、かなりの数のリソースが対応しているため、うまく使えば費用削減したりAWSの構成をシンプルにしたりすることができます。

共有するリソースに対して、どの単位でアクセス権を付与するかを示すプリンシパルのタイプは現状では以下が選択できるようです。

|プリンシパルタイプ|説明|
|:--|:--|
|AWSアカウント|指定したAWSアカウントと共有する|
|組織|指定した組織と共有する|
|組織単位|指定した組織と共有する（同一Organizations内）|
|IAMロール|指定したIAMロールと共有する|
|IAMユーザ|指定したIAMユーザと共有する|
|サービスプリンシパル|指定したサービスプリンシパルと共有する|

「**組織**」と「**組織単位**」の違いとしては、組織（`Organizations`）全体に共有するか、自分の組織内のOU単位で共有するかの違いとなります。

「**サービスプリンシパル**」については現状対応しているサービスが`AWS Private Certificate Authority`（プライベートCA）と`S3 Access Grants`というS3のアクセスコントロールの機能しかありませんが、指定したサービスプリンシパルに共有することで、例えばプライベートCAの情報をAWSと共有して使用したりするようなことができるようです。

現状RAMによる共有に対応しているリソース一覧は以下をご確認ください。

- [Shareable AWS resources](https://docs.aws.amazon.com/ram/latest/userguide/shareable.html)

# RAMによるリソース共有
ここからはRAMを使って実際にサブネットを共有して、共有したサブネットにEC2インスタンスを作成して通信できるかを確認してみます。

RAMの共有は指定したAWSアカウントや`AWS Organizations`の組織などを指定して共有します。

ただし、以下ドキュメントの共有可能リソース一覧のうち、「**Can share with accounts outside its organization**」の列が「**No**」のリソースについては同一`Organizations`内の組織にしか共有できない制限があり、今回共有するサブネットも制限に該当します。

- [Shareable AWS resources](https://docs.aws.amazon.com/ram/latest/userguide/shareable.html)

そのため今回は、以下のような`AWS Organizations`の構成で、`Root OU`直下に存在するルートアカウントから同一組織内の`SandBox OU`に存在するSandBoxアカウントに対してサブネットを共有するようにします。

![ram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/e1c2be94-a34e-ce6a-8688-390169d7d33e.png)

なお、今回の話の主題とは異なるため手順は省略しますが、共有するサブネットはルートアカウントのVPCに、事前に作成しておくものとします。

## AWS Organizationsの共有有効化
前述の通り今回共有しようとしている「**サブネット**」は組織にしか共有できませんが、デフォルトでは、`AWS Organizations`の組織への共有が無効化されているため、有効化します。

`AWS Organizations`の設定を行うことから、`AWS Organizations`を操作できるアカウント（通常はルートアカウント）で設定を行います。

「**Resource Access Manager**」ダッシュボードの「**設定**」から`AWS Organizations`にチェックを入れ、「**設定の保存**」を行います。

![Monosnap_20240706_163251.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/5531e510-eb3f-e405-3f6f-0c1b12b94ed4.png)

なお、一度チェックを入れて保存すると、設定がグレーアウトされ、本項目からはチェックを外せなくなりますが、チェックを元に戻したい場合は「**AWS Organizations**」ダッシュボードの「**サービス**」→「**RAM**」から「**信頼されたアクセスを無効にする**」を選択することで元に戻すことができます。

![Monosnap_20240706_165028.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/92b92885-1664-3ec7-913a-dccdbc1d095e.png)

## サブネットの共有
次は実際にRAMでサブネットを共有する設定を行います。

「**Resource Access Manager**」ダッシュボードの「**自分が共有**」の「**リソースの共有**」から「**リソース共有を作成**」を選択して以下のように設定した後、「**次へ**」を選択します。

|項目|設定|備考|
|:--|:--|:--|
|リソース共有の名前|root_account_subnet|※任意の名前を指定|
|リソース|サブネット|※一覧から共有したいサブネットを指定|
|タグ|※指定なし|今回は未指定|

![Monosnap_20240706_170748.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/cc9524df-52ec-2699-6026-83670d2f13ae.png)

リソースについては「**サブネット**」を選択すると、現在作成しているサブネット一覧が表示されるため、共有するサブネットのチェックボックスにチェックすることで、「**選択されたリソース**」に表示されます。

次ページの「**マネージド型アクセス許可を関連付ける**」は、対応しているリソースであれば、自分でアクセス許可の作成も行うことができますが、サブネットはカスタマー管理アクセス許可の作成に対応していないため、そのまま「**次へ**」を選択します。

![Monosnap_20240706_171535.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/50cddf54-8688-8720-0039-ed1537edd1f9.png)

次ページの「**プリンシパルにアクセス権限を付与する**」では、どの単位に対してアクセス権限を付与してリソースを共有するかを設定します。

以下「**プリンシパルタイプの選択**」では、上述したプリンシパルタイプが選択でき、AWSアカウントや組織ID等を直接指定して、「**追加**」を選択することで「**選択されたプリンシパル**」に指定したプリンシパルIDが表示されます。

![Monosnap_20240707_112848.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/d0b94c70-e306-e0b0-65ab-f7521a87b45d.png)

また、「**組織構造を表示**」のトグルボタンを有効にすると、以下のように組織構造から指定できるため、今回は以下のように設定します。

![Monosnap_20240707_113414.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/ac1d0b57-9970-55ca-24fb-2243dbd47843.png)

なお、設定が足りないのか、私の環境では上記`SandBox OU`配下に存在するはずの子OUやアカウントIDが表示されませんでした。

配下のOUやアカウントに共有する場合は、組織IDやアカウントIDを直接指定してください。

最後に確認画面が出るため、問題なければ「**リソース共有を作成**」で作成します。

ちなみに制限を無視して組織外AWSアカウントを指定したり、`AWS Organizations`との共有を有効にせずに共有しようとすると以下のようなエラーが表示されるため、もしエラーが表示された場合は`AWS Organizations`との共有設定を再度確認してみてください。

:::note alert
The resource share includes one or more resources that cannot be shared with accounts outside of your AWS organization.
:::

:::note alert
The resource you are attempting to share can only be shared within your AWS Organization. This error may also occur if you have not enabled sharing with your AWS organization, or that onboarding process is still in progress.
:::

## サブネット共有の確認
ルートアカウントからRAMで共有したサブネットが、SandBoxアカウント側で確認できるか確認してみます。

SandBox側のアカウントの「**VPC**」ダッシュボードの「**サブネット**」を見てみると、以下の画面には表示されていませんが、右にスクロールすると共有元のアカウントIDも確認することができます。

また、サブネットの詳細から「**共有**」タブを見ても、RAMで共有されたリソースであることが確認できます。

![Monosnap_20240707_115909.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/1c31e306-6b15-9411-0d5f-3c4b5498e49e.png)

今回サブネットを共有しましたが、サブネットと言いつつ、サブネットに紐づいているVPCやルートテーブル、インターネットゲートウェイ等のリソースも合わせて共有されているため、共有先となるSandBoxアカウント側で準備しなくてもそのまま使用できるようになっています。

以下、サブネットと一緒に共有されてきたインターネットゲートウェイの例。

![Monosnap_20240707_121148.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/35d32c41-3326-add6-0729-56078e4998fd.png)

## 疎通確認
サブネットを共有しましたが、共有したサブネットにEC2を作成して疎通してみたら通信できるのか確認してみたいと思います。

今回は以下のようにルートアカウント側とSandBoxアカウント側でそれぞれEC2を作成し、`Ping`等で疎通した場合、相手側EC2に届くのか確認します。

![ram_subnet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/81935152-ea82-74de-0b67-81589c7035b5.png)

結果としては、ルート側EC2（`10.1.0.43`）からもSandBox側EC2（`10.1.0.110`）からも問題なく通信できました。

```bash:ルートアカウント側EC2からのPing
[ec2-user@ip-10-1-0-43 ~]$ ping 10.1.0.110 -c 3
PING 10.1.0.110 (10.1.0.110) 56(84) bytes of data.
64 bytes from 10.1.0.110: icmp_seq=1 ttl=127 time=0.365 ms
64 bytes from 10.1.0.110: icmp_seq=2 ttl=127 time=0.422 ms
64 bytes from 10.1.0.110: icmp_seq=3 ttl=127 time=0.415 ms

--- 10.1.0.110 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2060ms
rtt min/avg/max/mdev = 0.365/0.400/0.422/0.034 ms
```

```bash:SandBoxアカウント側EC2からのPing
[ec2-user@ip-10-1-0-110 ~]$ ping 10.1.0.43 -c 3
PING 10.1.0.43 (10.1.0.43) 56(84) bytes of data.
64 bytes from 10.1.0.43: icmp_seq=1 ttl=64 time=0.489 ms
64 bytes from 10.1.0.43: icmp_seq=2 ttl=64 time=0.631 ms
64 bytes from 10.1.0.43: icmp_seq=3 ttl=64 time=0.441 ms

--- 10.1.0.43 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2049ms
rtt min/avg/max/mdev = 0.441/0.520/0.631/0.080 ms
```

# 共有されたリソースは共有された側から設定変更できるのか？
先に結論から言うと、できません。

編集しようとしても編集ボタンがグレーアウトされていたり、編集ボタンが無くなっていたりするためできません。
※以下は共有されたルートテーブルの画面例

![Monosnap_20240707_132453.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/ae98e38a-33f8-c741-9973-b080ad7dc738.png)

編集する場合は共有元の担当者に連絡して設定してもらいましょう。

# おわりに
今回は試験勉強がてら、AWS RAMを使用してリソース共有と共有したときの動きについてまとめてみました。

お客様のシステムを一から設計・構築する際、テスト用、本番用など大体環境ごとに複数のAWSアカウントに分けて、それぞれ同じようにリソースを作ることが多いですが、リソース共有用のアカウントを作っておき、全社的に使うリソースなどを共有用のアカウントから共有するというのも全社的なシステムを構築する場合、使えそうだなと感じました。

たまに資格勉強してみると色々と発見ができて面白いですね。

それにしても、前回「**AWS Certified Solutions Architect Professional**」の資格を取得したときは実務ではAWSをほとんど触ったことがなかったのに個人的には3年で大分変わったなぁ。