Oracle Cloud Infrastructureのアカウント構造とコンパートメントの使い方

### 初めに
OCIには、クラウドリソースを論理的に編成および分離する「コンパートメント」という概念があります。公式ドキュメントは以下から参照できます

https://docs.oracle.com/ja-jp/iaas/Content/Identity/Tasks/managingcompartments.htm

一方で、AWSではコンパートメントに相当する機能はなく、リソースの管理はアカウントやAWS Organizationsが近いものです。以下に、AWSとOCIにおけるアカウントの利用方法の違いを比較してまとめました。

|機能|	AWS|	OCI (Oracle Cloud Infrastructure)
|---|---|---
|アカウント|	各AWSアカウントは完全に独立しており、リソース、アクセス権限、請求情報はアカウントごとに管理。	|1つのOCIテナント（アカウント）内で、複数のコンパートメントを使用してリソースを論理的に分離したり管理したりできる。
|コンパートメント|	AWSには無い概念。AWSではアカウントやOrganizationsでリソースを分離している。	|1つのテナント(アカウント)内でリソースをグループ化する。アクセス制御やコスト管理もコンパートメント単位で行う。
|料金請求|	アカウントごとに請求が行われ、複数アカウントの料金を統合するためにAWS Organizationsの一括請求を使用する。	|1つのテナント内でのすべてのリソースの請求が行われ、コンパートメントごとにコスト管理。
|リソースの分離|	アカウントごとにリソースが完全に分離され、アカウント間でのリソース共有はクロスアカウントアクセス設定が必要。	|コンパートメントを使用してリソースを論理的に分離。テナント内でリソース管理や移動なども可能。
|アクセス制御|	IAMを使用して、アカウントごとにユーザー、グループ、ロールを設定。アクセスはアカウント内でのみ有効。	|IAMポリシーを使用して、コンパートメントごとにアクセス権限を設定。ユーザー、グループはテナントレベルで管理できる。

上記の違いを階層構造で表すと、以下のようになります。

**AWSのアカウント構成**
```
アカウント
 ├── 組織（Organizations）
 │    ├── 子アカウント1(Dev)
 │    │     ├── ユーザ/グループ
 │    │     └── 各種リソース（EC2, S3, RDS など）
 │    ├── 子アカウント2(Stg)
 │    │     ├── ユーザ/グループ
 │    │     └── 各種リソース（EC2, S3, RDS など）
 │    ├── 子アカウント3(Prd)
 │    │     ├── ユーザ/グループ
 │    │     └── 各種リソース（EC2, S3, RDS など）
 │    └── ...（複数の子アカウントが存在）
 └── 統合請求（Consolidated Billing）
       └── マスターアカウントで各子アカウントのコストを統合管理
```

**OCIのテナントとコンパートメント構成**
```
テナント（アカウント）
 ├── コンパートメント（ルート）
 │    ├── 親コンパートメント（Environments）
 │    │     ├── サブコンパートメント（Dev）
 │    │     │     ├── ユーザ/グループ
 │    │     │     └── 各種リソース（VCN, Compute, Object Storage, Database など）
 │    │     ├── サブコンパートメント（Stg）
 │    │     │     ├── ユーザ/グループ
 │    │     │     └── 各種リソース（VCN, Compute, Object Storage, Database など）
 │    │     └── サブコンパートメント（Prd）
 │    │           ├── ユーザ/グループ
 │    │           └── 各種リソース（VCN, Compute, Object Storage, Database など）
 │    └── ...（他のコンパートメント構成）
 └── 請求（Billing）
       └── 1つのテナント内で各コンパートメントのコストを一元管理
```

### 動作確認
コンパートメントの構成を実機で確認するために、OCIのリソース・マネージャでTerraformを使用して実際にリソースを作成してみました。今回は、3つのコンパートメント（StgとPrdとその上のEnvironment）を作成し、それぞれにVCNを1つずつ作成する簡単な構成を行いました。以下はその設定を示す図です。

![008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/7f07c3f6-5a68-bf4e-1946-ec9bd0b90741.png)

Terraformで実行した設定（.tfファイル）は以下の通りです：
```コンパートメント.tf
# OCIプロバイダーの設定（使用するリージョンを指定）
provider "oci" {
  region = "ap-tokyo-1" 
  auth   = "InstancePrincipal"
}

# 変数を定義して、テナントのOCIDを指定
variable "tenancy_ocid" {
  description = "The OCID of the tenancy root compartment"
}

# 親コンパートメント「Environments」を作成
resource "oci_identity_compartment" "environments" {
  name            = "Environments"  # コンパートメント名
  description     = "Parent compartment for different environments"
  compartment_id  = var.tenancy_ocid  # ルートコンパートメントID
}

# ステージング環境用のコンパートメント「Stg」を作成
resource "oci_identity_compartment" "stg" {
  name           = "Stg"  # コンパートメント名
  description    = "Compartment for staging environment"
  compartment_id = oci_identity_compartment.environments.id  # 親コンパートメントID
}

# 本番環境用のコンパートメント「Prd」を作成
resource "oci_identity_compartment" "prd" {
  name           = "Prd"  # コンパートメント名
  description    = "Compartment for production environment"
  compartment_id = oci_identity_compartment.environments.id  # 親コンパートメントID
}

# ステージングチームグループ「StgTeam」を作成
resource "oci_identity_group" "stg_team" {
  name            = "StgTeam"  # グループ名
  description     = "Staging team with access to Stg compartment"
  compartment_id  = var.tenancy_ocid  # ルートコンパートメントID
}

# 本番チームグループ「PrdTeam」を作成
resource "oci_identity_group" "prd_team" {
  name            = "PrdTeam"  # グループ名
  description     = "Production team with access to Prd compartment"
  compartment_id  = var.tenancy_ocid  # ルートコンパートメントID
}

# ステージングチームユーザー「stg_user1」を作成し、StgTeamに追加
resource "oci_identity_user" "stg_user1" {
  name            = "stg_user1"  # ユーザー名
  description     = "Staging team user"  # 説明
  email           = "stg_user1@example.com"  # メールアドレス
  compartment_id  = var.tenancy_ocid  # ルートコンパートメントID
}

# ステージングチームユーザーをStgTeamに追加
resource "oci_identity_user_group_membership" "stg_user1_membership" {
  user_id  = oci_identity_user.stg_user1.id  # ユーザーID
  group_id = oci_identity_group.stg_team.id  # グループID
}

# 本番チームユーザー「prd_user1」を作成し、PrdTeamに追加
resource "oci_identity_user" "prd_user1" {
  name            = "prd_user1"  # ユーザー名
  description     = "Production team user"
  email           = "prd_user1@example.com"  # メールアドレス
  compartment_id  = var.tenancy_ocid  # ルートコンパートメントID
}

# 本番チームユーザーをPrdTeamに追加
resource "oci_identity_user_group_membership" "prd_user1_membership" {
  user_id  = oci_identity_user.prd_user1.id  # ユーザーID
  group_id = oci_identity_group.prd_team.id  # グループID
}

# ステージング環境用のVCNを作成
resource "oci_core_vcn" "stg_vcn" {
  cidr_block     = "10.1.0.0/16"  # CIDRブロック
  display_name   = "Stg-VCN"  # VCN名
  compartment_id = oci_identity_compartment.stg.id  # コンパートメントID
}

# ステージング環境用のサブネットを作成
resource "oci_core_subnet" "stg_subnet" {
  cidr_block              = "10.1.1.0/24"  # サブネットのCIDRブロック
  display_name            = "Stg-Subnet"  # サブネット名
  compartment_id          = oci_identity_compartment.stg.id  # コンパートメントID
  vcn_id                  = oci_core_vcn.stg_vcn.id  # VCNのID
  prohibit_public_ip_on_vnic = true  # プライベートIPのみ許可
}

# 本番環境用のVCNを作成
resource "oci_core_vcn" "prd_vcn" {
  cidr_block     = "10.2.0.0/16"  # CIDRブロック
  display_name   = "Prd-VCN"  # VCN名
  compartment_id = oci_identity_compartment.prd.id  # コンパートメントID
}

# 本番環境用のサブネットを作成
resource "oci_core_subnet" "prd_subnet" {
  cidr_block              = "10.2.1.0/24"  # サブネットのCIDRブロック
  display_name            = "Prd-Subnet"  # サブネット名
  compartment_id          = oci_identity_compartment.prd.id  # コンパートメントID
  vcn_id                  = oci_core_vcn.prd_vcn.id  # VCNのID
  prohibit_public_ip_on_vnic = true  # プライベートIPのみ許可
}

# ステージングチームがStgコンパートメントにフルアクセスできるポリシーを作成
resource "oci_identity_policy" "stg_policy" {
  name            = "StgPolicy"  # ポリシー名
  description     = "Policy for StgTeam to access Stg compartment"
  compartment_id  = oci_identity_compartment.environments.id  # 親コンパートメント（Environments）のID
  statements = ["Allow group StgTeam to manage all-resources in compartment Stg"]  # ポリシーステートメント
}

# 本番チームがPrdコンパートメントにフルアクセスできるポリシーを作成
resource "oci_identity_policy" "prd_policy" {
  name            = "PrdPolicy"  # ポリシー名
  description     = "Policy for PrdTeam to access Prd compartment"
  compartment_id  = oci_identity_compartment.environments.id  # 親コンパートメント（Environments）のID
  statements = ["Allow group PrdTeam to manage all-resources in compartment Prd"]  # ポリシーステートメント
}
```

### 作成されたリソースの確認

#### ①コンパートメントの確認: 
親コンパートメント Environments 配下に作成された Prd と Stg という2つのコンパートメントを確認します。

 - 手順:
1. OCIコンソールにログインします。
1. メニューから「アイデンティティ」 > 「コンパートメント」を選択します。
1. コンパートメントの一覧から、親コンパートメント Environments を選択します。
1. コンパートメントの詳細ページで、Environments 配下に Prd と Stg の2つのサブコンパートメントが作成されていることを確認します。
 - 確認結果: 
下図のように、Environments コンパートメント配下に Prd と Stg のコンパートメントが作成されていることが確認できました。

![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/e3312fe2-0ab4-3761-317c-79c5fede65a3.png)

#### ②ユーザの確認
次に、ステージングチーム用のユーザー（例: stg_user1）と本番チーム用のユーザー（例: prd_user1）が正しく作成されているかを確認します。

 - 手順:
1. 「アイデンティティ」 > 「ドメイン」 > 「Defaultドメイン」 > 「ユーザー」を選択します。
1. 作成したユーザー stg_user1 と prd_user1 が一覧に表示されていることを確認します。
 - 確認結果:
以下の画像のように、stg_user1 と prd_user1 のユーザーが正しく作成されていることを確認できました。

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/a197f5eb-4277-82c1-70b4-290d305b1252.png)
から確認

#### ③ポリシーの確認
最後に、各コンパートメントへのアクセスを制御するために設定されたIAMポリシーが正しく設定されているかを確認します。

 - 手順:

1. 「アイデンティティ」 > 「ポリシー」を選択します。
1. ポリシーの一覧から、StgPolicy と PrdPolicy のポリシーを選択します。
1. 各ポリシーの詳細ページで、ポリシーステートメントが適切に設定されていることを確認します。

 - 確認結果: 
以下の画像のように、ポリシーが正しく設定されていることが確認できました。

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/00bc6386-6495-438a-176c-a3a8150eca4d.png)

### コンパートメントの動作確認
OCIのコンパートメント機能を使用すると、リソースの論理的な分離と管理が簡単に行えます。コンパートメント間では、リソースの移動が可能です。以下では、作成したVCN（AWSで言うVPC）を Stg コンパートメントから Prd コンパートメントに移動する手順を示します。

#### ①VCNの移動:
Stg-VCNをStgコンパートメントからPrdコンパートメントに移動するには、「リソースの移動」オプションを使用します。

 - 手順:

1. OCIコンソールで「ネットワーキング」 > 「仮想クラウドネットワーク（VCN）」を選択し、Stg-VCNを選択します。
1. 「アクション」メニューから「リソースの移動」を選択します。
1. 移動先のコンパートメントとして「Prd」を選択し、「移動」をクリックします。

![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/94ff9911-6414-fca6-33ad-88a8a1eb1c95.png)


![006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/43b010e3-600c-e37f-2ddb-80882e860fa8.png)

#### ②移動結果の確認
移動が完了したら、PrdコンパートメントにStg-VCNが正しく移動されていることを確認します。

 - 手順:

1. OCIコンソールで「ネットワーキング」 > 「仮想クラウドネットワーク（VCN）」を選択し、移動先のPrdコンパートメントを選択します。
1. Prdコンパートメント内にStg-VCNが表示されていることを確認します。
 - 確認結果:
 以下の画像のように、Stg-VCNがPrdコンパートメントに移動されていることを確認できました。


![007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322881/3ec21eb6-3ff9-9af8-7f85-de56840a5510.png)

### おわりに
AWSの機能と比較することでイメージをつかみながら学習できました。今後もOCIは楽しいので記事を書き続けようと思います。