Autonomous DatabaseでSAAS_ADMINユーザーのBreak glassアクセスを試してみた

# はじめに
Autonomous Databaseの11月の新機能でSaaSプロバイダ向けにSAAS_ADMINによるBreak Glassアクセスがサポートされました。
SAAS_ADMINユーザーはAutonomous Databaseに対してBreak Glass APIを実行したときにはじめて有効化されるユーザーです。顧客ごとにAutonomous Databaseを運用管理しているSaaSプロバイダは、正しい顧客の承認プロセスを経た場合にのみBreak Glass APIが実行させることで、SAAS_ADMINユーザによる緊急アクセスを可能にできます。

# Break Glass APIによるSAAS_ADMINの有効化
SAAS_ADMINユーザはアカウントがロックされており、管理ユーザであるADMINユーザでもアンロックはできません。
```
SQL> alter user saas_admin account unlock;
alter user saas_admin account unlock
*
ERROR at line 1:
ORA-01031: insufficient privileges
````

有効化にはBreak Glass APIを実行することが必要です。Break Glass APIはREST APIまたはCLIでのみ実行ができます。
 
 **REST API：[ConfigureSaasAdminUser](https://docs.oracle.com/en-us/iaas/api/#/en/database/20160918/AutonomousDatabase/ConfigureSaasAdminUser)**
 **OCI CLI: [configure-saas-admin-user](https://docs.oracle.com/en-us/iaas/tools/oci-cli/3.37.1/oci_cli_docs/cmdref/db/autonomous-database/configure-saas-admin-user.html)**
| パラメータ名 | 説明 |
|:-:|---| 
| REST: isEnabled <BR> CLI: --is-enabled| 有効化(TRUE)、無効化(FALSE)を指定  |
| REST: password <BR> CLI: --password | SAAS_ADMINのパスワード。パスワードではなくOCI Vaultのシークレット利用も可。その場合はpasswordを指定せず、secretId,secretVersionNumberを指定する  |
| REST: accessType <BR> CLI: --access-type | read-only（デフォルト）,read/write,adminから選択  |
| REST: duration <BR> CLI: --duration | 有効期間の指定。1時間（デフォルト）～24時間の範囲で指定  |

REST APIの例はドキュメントにあるので、ocicliで実行してみました。--access-type、--durationは指定していないので、この場合デフォルトのread-only、1時間となります。
```\
$ oci db autonomous-database configure-saas-admin-user --autonomous-database-id ocid1.autonomousdatabase.oc1.ap-tokyo-1.xxxxxxxxxxxxxxx --is-enabled true --password "Welcome12345##"
{
  "data": {
    "actual-used-data-storage-size-in-tbs": 0.003737926483154297,
    "allocated-storage-size-in-tbs": 0.0087890625,
    ：
    <略>
    :
    "vault-id": null,
    "whitelisted-ips": [
      "0.0.0.0/0"
    ]
  },
  "etag": "e533b567",
  "opc-work-request-id": "ocid1.coreservicesworkrequest.oc1.ap-tokyo-1.xxxxxxxxxxxxxxx"
}
```
# SAAS_ADMINのステータスの確認
ステータスは**getSaaSAdminUserStatus(REST API)**、**saas-admin-status(CLI)** で確認できます。CLIでまだ無効化されていない時点で確認するとこちらのような結果が返されました。

```
$ oci db autonomous-database saas-admin-user-status --autonomous-database-id ocid1.autonomousdatabase.oc1.ap-tokyo-1.xxxxxxxxxxxxxxx
{
  "data": {
    "access-type": "READ_ONLY",
    "is-enabled": true,
    "time-saas-admin-user-enabled": "2023-11-22T13:05:58.805000+00:00"
  }
}
```

またSQLでも確認できます。**DBA_CLOUD_CONFIG**ビューに対してパラメータ名にsaas_admin_accessを指定します。こちらは無効化予定の時間も確認できるようです。

```
SQL> SELECT JSON_QUERY(PARAM_VALUE, '$' PRETTY) FROM DBA_CLOUD_CONFIG WHERE PARAM_NAME = 'saas_admin_access' ORDER BY 1;

JSON_QUERY(PARAM_VALUE,'$'PRETTY)                                                                                                                                                                                        
---------------------------------------------------------------------------------
{
  "auth_grantor" : "\"C##CLOUD$SERVICE\"",
  "auth_role" : "READ_ONLY",
  "auth_begin" : "22-NOV-23 01.05.58.715349 PM UTC",
  "auth_duration" : "1 hour",
  "planned_auth_end" : "22-NOV-23 02.05.58.716313 PM UTC"
} 
```

# SAAS_ADMINの無効化
有効化するときに指定した期間が過ぎれば自動的に無効化が行われます。接続していたSAAS_ADMINユーザで無効化後SELECT文を打つとORA-3113が返りました。
```
SQL> select * from dba_cloud_config
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 3002
Session ID: 26448 Serial number: 8555
```

また有効期間のほかにconfigure-saas-admin-userで明示的に無効化させることも可能です。
```
$ oci db autonomous-database configure-saas-admin-user --autonomous-database-id ocid1.autonomousdatabase.oc1.ap-tokyo-1.xxxxxxxxxxxxxxx --is-enabled true --password "Welcome12345##"
{
  "data": {
    "actual-used-data-storage-size-in-tbs": 0.003737926483154297,
    "allocated-storage-size-in-tbs": 0.0087890625,
    ：
    <略>
    :
    "vault-id": null,
    "whitelisted-ips": [
      "0.0.0.0/0"
    ]
  },
  "etag": "4f605933",
  "opc-work-request-id": "ocid1.coreservicesworkrequest.oc1.ap-tokyo-1.abvwsljrz7lq2m577plwy6m2sq6cjdb7o6sjf5ddumu6ibyfl6754hqgvlqa"
```

無効化の状態では、ステータスはこちらのようになります。
```
$ oci db autonomous-database saas-admin-user-status --autonomous-database-id ocid1.autonomousdatabase.oc1.ap-tokyo-1.anxhiljrssl65iqaaxnj3alltnwg6p6ezjfvgv25tkrjzvxmanvwwjjjcjha
{
  "data": {
    "access-type": null,
    "is-enabled": false,
    "time-saas-admin-user-enabled": null
  }
}
```
SQLの場合は、無効化されると、無効化予定の時間(planned)と実際に無効化された時間(actual)が表示されました。

```
SQL> SELECT JSON_QUERY(PARAM_VALUE, '$' PRETTY) FROM DBA_CLOUD_CONFIG WHERE PARAM_NAME = 'saas_admin_access' ORDER BY 1;

JSON_QUERY(PARAM_VALUE,'$'PRETTY)                                                                                                                                                                                                                                                                        
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
{
  "auth_grantor" : "\"C##CLOUD$SERVICE\"",
  "auth_role" : "READ_ONLY",
  "auth_begin" : "24-NOV-23 03.47.43.416753 AM UTC",
  "auth_revoker" : "\"C##CLOUD$SERVICE\"",
  "auth_end" :
  {
    "planned" : "24-NOV-23 04.47.43.417753 AM UTC",
    "actual" : "24-NOV-23 03.55.37.335713 AM UTC"
  }
} 
```

# SAAS_ADMINユーザの監査
SAAS_ADMINユーザの監査情報は取られているのか、UNIFIED_AUDIT_TRAILビューを確認してみました。

```
select EVENT_TIMESTAMP,sessionid,dbusername,UNIFIED_AUDIT_POLICIES ,sql_text,authentication_type,CLIENT_PROGRAM_NAME from unified_AUDIT_trail where  EVENT_TIMESTAMP > current_date - 1/24 order by event_timestamp;

EVENT_TIMESTAMP           SESSIONID DBUSERNAME       UNIFIED_AUDIT_POLICIES SQL_TEXT                                          AUTHENTICATION_TYPE                                                                 CLIENT_PROGRAM_NAME                              
------------------------ ---------- ---------------- ---------------------- ------------------------------------------------- ----------------------------------------------------------------------------------- ------------------------------------------------ 
2023-11-24T03:47:43.124Z  233024164 C##CLOUD$SERVICE ORA$MANDATORY          AUDIT POLICY ADB_SAAS_ADMIN_AUDIT BY SAAS_ADMIN   (TYPE=(DATABASE));(CLIENT ADDRESS=((PROTOCOL=tcps)(HOST=10.0.6.0)(PORT=11570)));    oracle@e4pod-mrhui4 (S000)     ★ポリシー有効化                  
2023-11-24T04:50:33.758Z  536435971 SAAS_ADMIN       ADB_SAAS_ADMIN_AUDIT                                                                                                (TYPE=(DATABASE));(CLIENT ADDRESS=((PROTOCOL=tcps)(HOST=xxx.xx.xxx.xxx)(PORT=35472))); sqlplus@dev1 (TNS V1-V3) 
2023-11-24T04:50:33.850Z  536435971 SAAS_ADMIN       ADB_SAAS_ADMIN_AUDIT   SELECT DECODE(USER, 'XS$NULL',  XS_SYS_CONTEXT('XS$SESSION','USERNAME'), USER) FROM SYS.DUAL (TYPE=(DATABASE));(CLIENT ADDRESS=((PROTOCOL=tcps)(HOST=xxx.xx.xxx.xxx)(PORT=35472))); sqlplus@dev1 (TNS V1-V3) 
:
2023-11-24T04:52:38.945Z  536435971 SAAS_ADMIN       ADB_SAAS_ADMIN_AUDIT   select * from dba_cloud_config                                                               (TYPE=(DATABASE));(CLIENT ADDRESS=((PROTOCOL=tcps)(HOST=152.70.100.137)(PORT=35472))); sqlplus@aradev1 (TNS V1-V3) 
：
2023-11-24T05:01:25.825Z 3456745200 C##CLOUD$SERVICE ORA$MANDATORY          NOAUDIT POLICY ADB_SAAS_ADMIN_AUDIT BY SAAS_ADMIN                                            (TYPE=(DATABASE));(CLIENT ADDRESS=((PROTOCOL=unknown)(HOST=xxx.xxx.xxx.xx)));          oracle@e4pod-mrhui4 (J002)  ★無効化
```
有効化したときにADB_SAAS_ADMIN＿AUDITというポリシーが有効化され、その後のSAAS_ADMINユーザの実行した情報は監査情報として取得されていることがわかります。また無効化したときに、ポリシーも無効化されています。つまり、自動的に監査情報が取られるようです。

# おわりに
Autonomous DatabaseのSAAS_ADMINユーザによるBreak Glassアクセスの動作を確認してみました。緊急時に一時的にアクセスの許可を与えて対応させる必要がある場合にご検討ください。

# 参考資料
+ [Break Glass Access for SaaS on Autonomous Database](https://docs.oracle.com/en/cloud/paas/autonomous-database/serverless/adbsb/autonomous-break-glass.html#GUID-A974758C-7297-4D11-A719-BDA35F2A288E)