OCI IAMとBaseDBのトークン・ベースの認証連携①

前回でDatabase ClientはBaseDBにTLSで接続できるようになりましたので、ここからはIAMとトークン・ベースで認証連携させるための設定をしていきます。

## 1. IDENTITY_PROVIDER_TYPEの設定
OCI IAMとの認証連携機能を有効化するためには、データベース側のIDENTITY_PROVIDER_TYPEのパラメータをOCI_IAMに設定する必要がある。

```sql
-- Alter System文でIdentity ProviderをIAMに設定
SQL> ALTER SYSTEM SET IDENTITY_PROVIDER_TYPE=OCI_IAM SCOPE=BOTH;
SQL> SELECT NAME, VALUE FROM V$PARAMETER WHERE NAME='identity_provider_type';
NAME                      VALUE
------------------------  -------------
identity_provider_type    OCI_IAM
```



## 2. IAMグループとポリシーの作成

IAMトークンを使用してデータベースに接続するためには、そもそもIAMユーザーがBaseDBサービスを使用するための権限をIAMポリシーとして許可されていなければならない。

ここでは、そのサービスを使用できるポリシーを持つ**dbtoken_grp**というグループを作成し、**emp1**と**mgr1**というユーザーをそのグループに所属させる。

### IAMユーザーの作成
- IAMに**emp1**と**mgr1**のユーザーを二つ作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/5f187839-9ad9-a590-c31d-c8ec4e961143.png)




### グループとポリシーの作成
- グループを作成 -> グループ名: **dbtoken_grp**
- データベースの権限をグループに付与したポリシーを作成 -> ポリシー名: **dbtoken_pol**
<font color="red">allow group dbtoken_grp to use database-connections in tenancy </font>
<font color="red">allow group dbtoken_grp to use database-family in tenancy</font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/9bb9882e-f8a4-21ff-ccc9-b50de9bae4c7.png)

- 作成したグループにemp1とmgr1ユーザーを割り当てる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/8a685ac1-a860-0ac8-26fe-4af11d401d68.png)

## 3. クライアントの設定
今回のテストでは、IAMの二つのユーザー(emp1とmgr1)をOCIのコンフィグで切り替えてDBアクセストークンを取得し、それぞれのIAMユーザーのトークンを用いてDBに接続する。そのための必要なOCI Cliの実行環境の設定を行う。

### OCI Cliでアクセス・トークンを取得する設定

```shell
#clientにopcで接続
#oci cliのインストール
$ sudo pip3 install oci-cli

#oci cliの接続設定
$ oci setup config
Enter a location for your config [/home/opc/.oci/config]: --> Enter
Enter a user OCID: ocid1.user.oc1..xxxxxxxx　--> emp1のOCID
Enter a tenancy OCID: ocid1.tenancy.oc1..xxxxx
Enter a region by index or name  
Do you want to generate a new API Signing RSA key pair? (If you decline you will be asked to supply the path to an existing key.) [Y/n]: Y
Enter a directory for your keys to be created [/home/opc/.oci]: --> Enter
Enter a name for your key [oci_api_key]: --> Enter
Enter a passphrase for your private key ("N/A" for no passphrase): -->N/Aと入力

#oci configのPublic Keyをコピー
$ cat /home/opc/.oci/oci_api_key_public.pem 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxuxnwAZVRFVVi4yVu9BZ
vFifL/KVtMQWoY5pjomLxMgyoYeSydjThxui6EHEbdxGhvo0BgmiWcNFQI603jL1
oXkkUO8+IcNETslW4bffoCwiGrcAlZ/u*****
-----END PUBLIC KEY-----

```

 - 作成した**emp1**ユーザーのAPIキーとして追加する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562423/b80e3a85-8496-6b54-1bb2-0810ade2f286.png)


```shell
#ociコマンドを実行し、結果が表示されればOK
$ oci iam region list --output table
+-----+-------------------+
| key | name              |
+-----+-------------------+
| AMS | eu-amsterdam-1    |
| ARN | eu-stockholm-1    |
```
IAMユーザーを切り替えてアクセストークンを取得するテストを行うので、emp1とmgr1でそれぞれconfigを切り替えて接続できるようにする

```shell
#emp1の接続キーをemp1フォルダにまとめ、configを変更
$ mkdir /home/opc/.oci/emp1
$ mv /home/opc/.oci/oci_api_key* /home/opc/.oci/emp1
$ vi /home/opc/.oci/config
[emp1] <--名前変更
user=ocid1.user.oc1..xxxxxxxx
fingerprint=e1:dd:32:10:0c:b5:4d:8e:93:63:05:27:be:64:0e:38 
key_file=/home/opc/.oci/emp1/oci_api_key.pem　<--ディレクトリ変更
tenancy=ocid1.tenancy.oc1..xxxxxxxx
region=ap-tokyo-1

#今度はmgr1でconfigの設定を行う
$ oci setup config
Config file: /home/opc/.oci/config already exists. Do you want add a profile here? (If no, you will be prompted to overwrite the file) [Y/n]: --> Enter
Enter the name of the profile you would like to create: mgr1
以降は前回と同じ。作成後は同様にPublic KeyをAPIキーとしてmgr1に登録する

#mgr1の接続キーをmgr1フォルダにまとめ、configを変更
$ mkdir /home/opc/.oci/mgr1
$ mv /home/opc/.oci/oci_api_key* /home/opc/.oci/mgr1
$ vi /home/opc/.oci/config
[mgr1]
user=ocid1.user.oc1..xxxxxxxx
fingerprint=f1:37:19:5a:58:48:55:63:42:ee:74:61:95:5d:c0:10
key_file=/home/opc/.oci/mgr1/oci_api_key.pem <--ディレクトリ変更
tenancy=ocid1.tenancy.oc1..xxxxxxxx
region=ap-tokyo-1

#IAMユーザーの切り替えはOCI_CLI_PROFILEの変数で行う。それぞれのユーザーでDBアクセストークンを取得するociのコマンドが実行できるかどうかを確認しておく
$ export OCI_CLI_PROFILE=emp1
$ oci iam db-token get
Private key written at /home/opc/.oci/db-token/oci_db_key.pem
db-token written at: /home/opc/.oci/db-token/token　　　<-- トークンが格納されているディレクトリ
db-token is valid until 2024-01-28 05:46:42

$ export OCI_CLI_PROFILE=mgr1
$ oci iam db-token get
iam db-token get
Private key written at /home/opc/.oci/db-token/oci_db_key.pem
db-token written at: /home/opc/.oci/db-token/token
db-token is valid until 2024-01-28 05:50:48
```

### Oracle Database Clientのトークン認証の設定
クライアント側のtnsnames.oraにトークン認証の接続文字列を追加する


```sql
$ vi /home/opc/instant19c/tnsnames.ora

接続文字列 =
   (description= (retry_count=20)(retry_delay=3)
      (address=(protocol=tcps)(port=1522)(host=ホスト名))
      (connect_data=(service_name=サービス名))
      (security=(ssl_server_dn_match=yes)(TOKEN_AUTH=OCI_TOKEN))
   )
   
<例>
iam =
   (description= (retry_count=20)(retry_delay=3)
      (address=(protocol=tcps)(port=1522)(host=testdb2))
      (connect_data=(service_name=db0131_pdb1.sub01120452410.vcnaqua.oraclevcn.com))
      (security=(ssl_server_dn_match=yes)(TOKEN_AUTH=OCI_TOKEN))
   )

````

## 4. IAMユーザーとのDBスキーマのマッピング
IAMユーザーがトークンでDB認証されると、Databaseは最終的には何らかのDBスキーマにマッピングしなければならない。マッピングの方式は、排他的スキーマと共有スキーマの２種類あるが、ここでは一番簡単な排他的マッピングでトークン認証の設定が正しくできているかどうかの基本的な動作確認を行う。
排他的マッピングとは、IAMユーザとDBスキーマを1:1でマッピングする方法

```sql
-- 排他的マッピングユーザーの作成
CREATE USER emp1 IDENTIFIED GLOBALLY AS 'IAM_PRINCIPAL_NAME=emp1'; -- DBスキーマ:emp1 = IAMユーザ:emp1
grant connect to emp1; -- connect権限を付与
```

## 5. opensslのパッケージをインストール
19c以降のOracle Databaseでは、libcrypto.so.10、libssl.so.10のライブラリが入っておらず、トークン認証のフローでエラーになる。内容はDBのアラートログで確認できるが、以下のパッケージをBaseDBにインストールしておくこと

```shell
$ sudo yum install  compat-openssl10 
```
※BaseDB 23cの場合、libauth_sdk_iam.soの不足で接続できない場合がある。アラートログで確認。回避策としては、19cから$ORACLE_HOME/lib/libauth_sdk_iam.soをコピーし、23cにコピーする。


## 6. 接続テスト 
トークンを使用してDBに接続できることを確認する

```shell
#emp1ユーザーのOCIプロファイルに変更
$ export OCI_CLI_PROFILE=emp1

#DBトークンを取得
$ oci iam db-token get
Private key written at /home/opc/.oci/db-token/oci_db_key.pem
db-token written at: /home/opc/.oci/db-token/token
db-token is valid until 2024-01-31 14:12:43

#トークン・ベースで接続
$ sqlplus /@iam
Connected to:
Oracle Database 19c EE High Perf Release 19.0.0.0.0 - Production
Version 19.21.0.0.0
SQL> show user
USER is "EMP1"  #DBスキーマ EMP1にマッピングされた
```
データベースへの接続は、下記のようなフローで動作する
① DB Clientは、**oci iam db-token get**でemp1ユーザーのDBトークンを取得する。トークンは.oci/db-token/tokenに出力される
② データベースに**sqlplus /@接続文字列**で接続することでトークンをTLSでDatabaseに送信する
③ DatabaseはトークンをValidationし、トークンに含まれるユーザーIDのグループをチェックし、最終的にDBスキーマにマッピングする


## 7.トラブルシューティング
手順通りに実施しても一発で接続成功することは難しいかもしれないので、どの部分の問題なのか段階的に調査するのが良い
 - クライアント側のSQL Traceのログからアクセストークンは正しく取得できているか？
 - Databaseのアラートログにエラーは出力されていないか？
 - IAMのグループやユーザーは適切に設定されているか？
 - DatabaseとIAMのマッピングユーザーは適切か？
 - OS側、OCI側のFirewallで必要なポートをブロックしていないか？
 - サポートされているバージョンのDatabase Clientを使用しているか？

次回は、より実践的なIAMのグループとDatabaseの共有スキーマをマッピングする手順について紹介します。