Oracle Cloud Infrastructure Architect Associate 勉強メモ（IAMとコンパートメント ポリシー)

# IAMの概要
認証(AuthN)と認可(AuthZ)でリソース[^リソース]に対するアクセス制御を行う。

[^リソース]: OCIで利用できるサービスや機能のこと（ストレージサービス、ネットワーキングサービスなど…）

:::note info
認証：どのユーザか？（誰か？）
認可：何が許可されているか？（何ができるか？）
:::

# リソースの識別
リソースに対するアクセス制御を行うためには**リソースを識別**しないといけない。
Oracleではすべてのリソースには**OCID**が割り当てられている。これによりリソースを識別することができる。
OCIDは形式が決められている。構文は以下の通り
`ocid1.<RESOURCE TYPE>.<REALM>.[REGION].<UNIQUE ID>`

<details><summary>各要素について</summary>

- ocid1
OCIDのバージョンを示すリテラル文字列。（基本ocid1な気がする？）
- **resource type**
リソースのタイプ(例: tenancy、instance、volume、vcn、subnet、user、groupなど)を指定する。
**ここを見れば何のリソースなのか判別できる。**（~~重要なのはここだけ~~)
- realm
リソースが存在するレルム。レルムはリージョンの論理的な集合体のこと。
商用レルムを表すoc1、Government Cloud（政府の情報システム用クラウドサービス）レルムを表すoc2、Federal Government Cloud（こちらも政府向け？調べてもよくわからなかった）レルムを表すoc3がある。
（日本政府向けでもOracleが一部使われるようになったらしい）
- region
リソースが存在するリージョン(たとえば、phx、iad、eu-frankfurt-1など)。
- unique ID
IDの一意の部分。自動的にランダムなIDが割り振られる。
</details>

:::note info
OCIではリソースをOCIDで識別する。
OCIDのresource typeを見るとそのリソースが何のリソースなのかわかる。
:::

# AuthN（認証）
認証は各**プリンシパル**をグループ化し、**グループに対して認証を行う。**
ユーザ等の認証に用いられる情報を**クレデンシャル**という。
（IAM認証でいうユーザー名とパスワードなど）

<details><summary>プリンシパルについて</summary>
ユーザーやリソースにアクセスするインスタンスなどの**認証対象**
プリンシパルには以下の３種類がある。
- ユーザー
個人やアプリケーション自体。
グループで管理。（複数のグループに所属することも可能）
- リソース（インスタンス）プリンシパル
OCIのリソースやOCIサービスに対してAPIコールを行うインスタンスなど。
動的グループで管理。
https://speakerdeck.com/ocise/ociji-shu-zi-liao-idoyobiakusesuguan-li-iam-xiang-xi?slide=10
- サービスプリンシパル
OCIサービスをまとめたもの。あらかじめ登録されており、ユーザーによる追加はできない。
</details>


認証方法には以下の3つがある。
- IAM認証
ユーザー名とパスワードで認証を行う。
ユーザー名が必要なため**ユーザー（人間）に対してのみ**。
パスワードのリセットやマルチファクタ認証などもWEBコンソール上で行える。
- API署名キー
**インスタンス**などはIAM認証ができないのでこれを用いる。
公開キーを登録し秘密鍵で認証。
- 認証トークン
API署名キーがサポートされていない場合（Google、Xなどが提供する**サードパーティーAPI向け**）
各ユーザーが同時に**最大2つの認証トークンを持つことが可能。** 

:::note info
プリンシパルをグループ化して**グループに対して**リソースへの認証を行う。
認証方法は**IAM認証**、**API署名キー**、**認証トークン**の３つがある。
認証時に用いる情報を**クレデンシャル**と呼ぶ。
:::

# アイデンティティ・ドメイン
認証ではプリンシパルをグループ化する必要があるが、認証するユーザーやグループなどの管理を行うには**アイデンティティ・ドメイン**と呼ばれる概念が存在する。

ユーザー、グループ、動的グループなどを束ね管理するためのものなので、**ポリシーやコンパートメント、ネットワークソースなどは含まれない**。（**認証なのでリソース側ではない**）

<details><summary>アイデンティティ・ドメイン補足</summary>
従来はIAM（OCI特化の認証基盤）とIDCS（他のOracleサービス用認証基盤）という２つの認証基盤が存在しており、これらを1つに統合した認証基盤（認証機能）がアイデンティティ・ドメイン。
</details>

:::note info
認証するユーザーやグループなどの管理を行う概念。
ユーザー、グループ、動的グループなど認証対象を束ね管理するためのもの。
:::

# 動的グループ（Dynamic Group)
インスタンスなど（ユーザ以外）をグループ化したもの。
マッチングルールがあり、それに当てはまるものは**自動的**にグループに入る。

![動的グループ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491422/8eebc975-cea9-d1e8-0f97-b6625a51b829.png)


例：インスタンスのコンパートメントIDに'ocid'とついていたら
`Any {instance.compartment.id = 'ocid'}`

:::note info
ユーザ以外のプリンシパルをグループ化したもの。
マッチングルールを設定し、当てはまった場合自動的に動的グループに入る。
:::

# AuthZ（認可）
グループ、動的グループに対してアクセス許可を与える。（認可されているリソースにアクセスできる）
- **最小権限の原則**という概念
デフォルトでは何の操作も許可されていない。
**ポリシー**でリソースに対するアクセス（できること）を許可していくイメージ。

## ポリシーの書き方
認可の内容を制御するための設定を記述する。
構文は以下の通り
`Allow <subject> to <verb> <resource-type> in <location> where <conditions>`
**<font color="red">Subject（誰が）** to  **<font color="blue">verb（何を）</font><font color="green">resorce-type（何に対して）</font>** in  **<font color="orange">location(どのコンパートメントの)</font>** where  **conditions(どういった条件のとき)**
https://docs.oracle.com/ja-jp/iaas/Content/Identity/Concepts/policysyntax.htm
- <font color="red">Subject句（誰が）</font>
  グループ名（OCIサービスの場合はサービス名）と名前又はOCIDでグループ・サービスを指定する。
  複数のグループ名またはグループ名の場合は、カンマで区切って指定する。
  例：`group a, b`
 `any-user`ですべてのユーザーにも適用可能。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491422/94736199-b992-5dc9-cd1a-7f49164e26a1.png)

<details><summary>構文</summary>

- グループ
`group <group_name>`
`group id <group_ocid>`
- 動的グループ
`dynamic-group <dynamic-group_name>`
`dynamic-group id<dynamic-group_ocid>`
- すべてのユーザー
`any-user`
 </details>    
      
:::note info
どのグループに対して認証を行うか指定する。
構文：グループの種類<グループ名 or OCID>
:::
　
- <font color="blue">Action句（どのリソースの何を許可する）</font>
  ポリシーの`verb`から`resorce-type`までの部分
<details><summary>verb（動詞、何を許可するか）</summary>
全部で4種類。上に行くほど権限が強くなる。

- manage（管理する）
リソースのすべての権限。（リソースの作成・削除など）
- use（使う）
リソースの変更。
- read（読み取る）
上記に加えメタデータも読み取り可能。
- inspect（検査する）
メタデータ（機密情報など）以外を読み取り可能。外部監査向け
</details>  

<details><summary>resorce-type（何に対して）</summary>

リソースタイプを指定する。以下の３種類。

- 個々のリソース・タイプ(vcns、subnets、instances、volumesなど)。
- ファミリ・リソース・タイプ(virtual-network-family、instance-family、volume-familyなどリソースの種類の集合体)。
- all-resources：コンパートメント(またはテナンシ)内のすべてのリソースを対象
</details>  

以下のスライドがわかりやすい。
https://speakerdeck.com/ocise/ociji-shu-zi-liao-idoyobiakusesuguan-li-iam-gai-yao?slide=13
    
       
:::note info
どのリソースの何を許可するかを表す。
何を(verb): manage, use, read, inspect
リソース（resorce-type）：個々のリソース・タイプ, ファミリ・リソース・タイプ, all-resources
:::

### Permissions(権限)について
AuthZの原子単位。これを用いるとverbごとにさらに細かく設定が可能。
ポリシーでは動詞とリソースタイプを指定するが、それらを指定した際にPermission(とAPI操作)が付与されるイメージ。

|verb+resorce type|Manage Volumes|Use Volumes|Read Volumes|Inspect Volumes|
|:--:|:--:|:--:|:--:|:--:|
|Permission|VOLUME_INSPECT VOLUME_UPDATE VOLUME_WRITE VOLUME_CREATE VOLUME_DELETE VOLUME_MOVE|VOLUME_INSPECT VOLUME_UPDATE VOLUME_WRITE|VOLUME_INSPECT|VOLUME_INSPECT|
|API|CreateVolume DeleteVolume ChangeVolumeCompartment|AttachVolume DetachVolume|No extra|ListVolume GetVolume|

<details><summary>例：ボリュームに対するポリシー</summary>

ここでmanageの権限は与えたいが、delete（削除）の権限は与えたくないといった場合、where句でPermissionを制御する。

パターン１：delete以外の権限を与える。
`Allow group XYZ to manage groups in tenancy where any {
request.permission=‘VOLUME_INSPECT’,
request.permission=‘VOLUME_CREATE’,
request.permission=‘VOLUME_WRITE’,
request.permission=‘VOLUME_UPDATE’,
request.permission=‘VOLUME_MOVE’ }`
パターン２：deleteのみ権限を付与しない。
`Allow group XYZ to manage groups in tenancy where
request.permission != ‘VOLUME_DELETE’`
※request.permission：リクエストを送った側のpermissionに
</details>

:::note info
verbはPermissionsという細かい権限の集合であり、Where句で権限を与えることができる。
request.permissionでリクエストを送った側のpermissionに権限を付与できる。
:::

- <font color="orange">in句（location)</font>
  名前またはOCIDで単一の[コンパートメント](#コンパートメント)またはコンパートメント・パスを指定する。
複数のコンパートメントを指定するには、別のポリシーを作成する必要あり。
テナンシ（アカウントに割り当てられた領域。テナンシを分割したものがコンパートメント）
<details><summary>構文</summary>

`tenancy` 
`compartment <compartment_name>`
`compartment id <compartment_ocid>`
</details>

:::note info
どのコンパートメントか（テナンシで指定も可能）を表す。
コンパートメント名かそのパス、またはtenancyで指定する。
:::

- Where句（conditions）
○○から始まるリソースなど、条件を設定する。
<details><summary>構文</summary>

- 単一条件の場合
`比較したい値 = 値`
`比較したい値 != 値`
- 複数条件の場合
or条件
`any{比較したい値 = 値}`　
and条件
`all{比較したい値 = 値}`　

比較する値の書き方
- 文字列
`'johnsmith@example.com'`
- パターン
「*」はワイルドカードとして扱う。
`/HR*/ (「HR」で始まる文字列と一致します)`

`/*HR/ (「HR」で終わる文字列と一致します) `

`/*HR*/ (「HR」を含む文字列と一致します) `
 </details>  
 
:::note info
条件を指定する。
or条件はany and条件はallで指定する。
文字列の指定も可能。パターン検索の場合はスラッシュで文字列を囲い、「*」はワイルドカードとして扱う。
:::



# コンパートメント
## 概要
ポリシーで認可するリソースのコンパートメントを指定していたが、このコンパートメントとは **リソースを束ねる概念** のことである。
リソースは1つのコンパートメントに属す。（**複数のコンパートメントに属すことはできない**）

### コンパートメントの特徴
- **入れ子構造**
    最初に作られるテナンシ（ルート・コンパートメント）の中に入れ子することができる（テナンシを含まず6個）
    **上位のコンパートメントに適用されるポリシーは下位のコンパートメントにも適用される。**（コンパートメントは親コンパートメントからポリシーを継承する。最低限のポリシーを適用することが必要。）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491422/42329a28-c209-14e3-db8c-fba8b18d97ed.png)

-  **複数のリージョンにまたがれる**（グローバルである）
他のリージョンにあるリソースも束ねられる。

- コンパートメントごとにリソースの使用量や予算を設定することもできる

### ポリシーのアタッチ
 コンパートメントに対してポリシーをアタッチすることができる（ポリシーを適用するには**コンパートメントにアタッチ**する必要がある。）
    上位のコンパートメントにあるポリシーはそのコンパートメントでポリシーを管理する権限がないユーザでは編集・削除はできない。
### **リソースの移動**
リソースは１つのコンパートメントにしか属せないが、別のコンパートメントに移動することができる。

<details><summary>コンパートメントエクスプローラー</summary>
コンパートメント内のリソースを一覧で表示できる。
全てのリージョンのリソースが閲覧可能。
</details>

:::note info
- コンパートメントはリソースを束ねる概念。
- リソースはいずれか１つのコンパートメントに属する。**複数のコンパートメントには属すことができない**が、別のコンパートメントに移動することはできる。
- ポリシーはコンパートメントごとに適用する。
- コンパートメントは入れ子構造にすることができ、上位のコンパートメントにアタッチされたポリシーは下位のコンパートメントにも適用される。
- コンパートメントはグローバルなリソースである。（他リージョンのリソースも束ねられる）
:::

# ネットワークソース
ポリシーではアクセスできるIPアドレスの範囲を指定することもできる。
IPアドレスの範囲を指定しネットワークソースに定義し、ポリシーのwhere句でアクセスを制御する。
例：corpnetという名前で定義したIPアドレス範囲からのアクセス（リクエスト）で○○というグループに属している場合、テナンシの××にmanageの権限を与える。
`allow group ○○ to manage ×× in
tenancy  where
request.networkSource.name='corpnet'`

:::note info
ネットワークソースを利用することでIP制限をかけることができる。
request.networkSource.nameでネットワークソースの名前を指定できる。
:::
# タグに基づくアクセス制御
リソースにタグをつけ、そのタグを元にアクセスを制御する。
タグは以下の３つの要素から成り立つ。
- タグ・ネームスペース：タグ・キーのコンテナ(集合）
- キー：タグを参照するためのもの
- タグ値：キーに与えたvalue

### リクエスト側リソースに適用されるタグ（グループ、動的グループ、コンパートメント）
request.principal.○○.tagの形で記載。
#### グループ
request.principal.group.tag.{tagNamespace}.{tagKeyDefinition}= '<value>'

例：
subject:すべてのユーザー
resorce-type:コンパートメント"HR"のインスタンスに対して
verb:manageの権限を与える。
conditions：グループタグに"Prod"というタグが付いていること。
`allow any-user to manage instances in compartment HR where request.principal.group.tag.Operations.Project= 'Prod'`


#### アクセスをリクエストする(インスタンスの)動的グループ
    request.principal.group.tag.{tagNamespace}.{tagKeyDefinition}= '<value>'
例：コンパートメント"HR"のインスタンスに対してmanageの権限を与える。条件として、"InstancesA"という動的グループに含まれており、グループタグに"Prod"というタグが付いていること。
`allow dynamic-group InstancesA to manage instances in compartment HR where request.principal.group.tag.Operations.Project= 'Prod'`
#### 動的グループ内のリソースが常駐するコンパートメント
    `request.principal.compartment.tag.{tagNamespace}.{tagKeyDefinition}= '<value>'`
例：動的グループInstancesAのメンバーであり、Operations.Project='Prod'でタグ付けされたコンパートメント内にも常駐するインスタンスは、テナンシ内のインスタンスを管理できる。
allow dynamic-group InstancesA to manage instances in tenancy where request.principal.compartment.tag.Operations.Project= 'Prod'

:::note info
request.<font color=red>principal</font>.<font color=blue>○○</font>.tag.{tagNamespace}.{tagKeyDefinition}
:::


### ターゲット・リソース（リクエスト対象）に適用されるタグ（コンパートメント、リソース）
 request.resource.○○.tagの形で記載。例は省略。
- リソース
    ```target.resource.tag.{tagNamespace}.{tagKeyDefinition}='<value>'```
- コンパートメント
`target.resource.compartment.tag.{tagNamespace}.{tagKeyDefinition}='<value>' ` 

:::note info
request.<font color=red>resource</font>.<font color=blue>○○</font>.tag.{tagNamespace}.{tagKeyDefinition}
:::

# 参考資料
- IAM

https://speakerdeck.com/ocise/ociji-shu-zi-liao-idoyobiakusesuguan-li-iam-gai-yao

https://speakerdeck.com/ocise/ociji-shu-zi-liao-idoyobiakusesuguan-li-iam-xiang-xi