2024年3月7日木曜日

ORDS Database APIをローカルの環境で有効にする

Apple Mシリーズ上でコンテナ・イメージから作成した、ローカルのAPEX環境でORDS Database APIを有効にしてみました。その際の作業ログを残しておきます。

こちらの記事の手順で作成した直後から作業を始めます。

環境を作成した直後はワークスペースが作成されていません。APEXの管理サービスに接続し、ワークスペースを作成します。


管理者ユーザーパスワード@apxchpwdを実行したときに設定しています。管理者ユーザー名のデフォルトはADMINです。


ワークスペースが未作成であるため、Oracle APEXへようこその画面が開きます。ワークスペースの作成をクリックしても同じ作業になりますが、今回はワークスペースを2つ作る予定なのでワークペースの管理を開きます。


ワークスペースの管理画面が開きます。最初に既存のワースペースを確認し、その後にワークスペースの作成を実施します。


Oracle APEXをインストールするとINTERNALというワークスペースが作成されます。Oracle APEXの管理ツールや開発ツールは、このINTERNALワークスペースに作成されているAPEXアプリケーションになります。


ワークスペースの管理画面に戻り、ワークスペースの作成をクリックします。

ワークスペース名を指定します。今回はapexdevとしています。ワークスペースIDは開発環境を作成するときに指定します(こちらの記事で説明しています)。今回は指定しません。

へ進みます。


既存スキーマの再利用いいえを選択し、ワークスペースに紐づくスキーマを新規作成します。スキーマ名apexdevとします。領域割当て制限(MB)10000を選択します。Oracle Database 23c Freeが持てるユーザー・データの上限が12GBなので、ほぼ上限いっぱいまでこのスキーマはデータが持てることになります。

スキーマのパスワード必須項目なので設定しますが、APEXはこのパスワードを使いません。他のツールよりデータベースに接続する際に使用します。

へ進みます。


ワークスペースの管理者のユーザー名管理者のパスワードを設定します。電子メールも必須項目なので合わせて設定します。

Autonomous Databaseと異なりオンプレミスの環境では、管理者ユーザーや開発者ユーザーはデータベースのアカウントではなく、Oracle APEXで管理します。

へ進みます。


確認画面が開きます。ワークスペースの作成を実行します。


ワークスペースが作成されました。完了します。


同じ作業を繰り返し、ワークスペースapexdev2を作成します。紐づけるスキーマはapexdev2として作成します。

既存のワークスペースを開き、INTERNALAPEXDEVAPEXDEV2の3つのワークスペースが作成されていることを確認します。


作成したワークスペースAPEXDEV2の方です)にサインインし、検証に使用する設定を行ないます。


初回接続時は管理者のパスワードの変更を求められます。パスワードの変更を実施し、ワークスペースへサインインします。


ワークスペースに含まれるアプリケーション一覧を取得するORDS Database APIを呼び出したときに、結果が返されるようにアプリケーションを作成します。空のアプリケーションで十分です。

アプリケーション・ビルダーを開きます。


作成をクリックします。


作成するアプリケーションの名前確認用アプリとします。

アプリケーションの作成をクリックします。


アプリケーションが作成されました。ワークスペースAPEXDEV2での作業は終了です。

これからワークスペースAPEXDEVを対象としてORDS Database APIを発行し、ワークスペースAPEXDEV2に作成されているアプリケーション一覧を取得するために必要な設定を行ないます。


ワークスペースAPEXDEV2からサインアウトし、ワークスペースAPEXDEVにサインインします。APEXDEV2のときと同様に、初回はパスワードの変更を求められます。


ワークスペースAPEXDEVに管理者ユーザーでサインインしました。SQLワークショップからRESTfulサービスを呼び出し、ワークスペースに紐づいているスキーマAPEXDEVをORDSに登録します(ORDSの用語ではREST有効化という作業になります)。


ORDSにスキーマを登録をクリックします。


ORDSスキーマ属性を保存します。RESTfulアクセスの有効化オンスキーマ別名apexdev(通常ワークスペース名と同じ名前にします)、(RESTfulサービスの呼び出しの確認に使用するため)サンプル・サービスのインストールオンにします。

スキーマ属性の保存をクリックします。


RESTfulサービスの画面が開きます。

左ペインよりサンプル・サービスとしてインストールされたモジュールoracle.example.hrのテンプレートversionのメソッドGETを選択します。


このメソッドの完全なURLを確認します。

http://localhost:8181/ords/apexdev/hr/version/


手元のPCからcurlコマンドを実行し、REST APIを呼び出してみます。

curl http://localhost:8181/ords/apexdev/hr/version/

レスポンスとして { "version": "23.1" } が返されます。

% curl http://localhost:8181/ords/apexdev/hr/version/

{"version": "23.1"}

% 


作成したローカルの環境でREST APIを受け付けることが確認できました。

続いてSQLワークショップSQLコマンドから、このREST APIを呼び出します。

Oracle APEXをインストールした直後は、ネットワークACLの設定がされていません。Oracle APEXはバージョンごとにスキーマを作成し、そのスキーマにデータベース・オブジェクトを作成します。Oracle APEX 23.2であれば、インストール先のスキーマはAPEX_230200になります。

以下のSELECT文によりスキーマAPEX_230200に設定されているネットワークACLを確認します。
select host, acl,
decode(dbms_network_acl_admin.check_privilege_aclid(aclid, 'APEX_230200','connect'), 1, 'GRANTED', 0, 'DENIED', NULL) privilege
from dba_network_acls;

PRIVILEGEnullです。

(Oracle SQL Developer Extension for VS Codeの画面です)


以下のスクリプトを実行し、すべての宛先を対象としてconnectresolveの権限を与えます。
begin
    dbms_network_acl_admin.append_host_ace(
        host => '*',
        ace => xs$ace_type(
            privilege_list => xs$name_list('connect','resolve'),
            principal_name => 'APEX_230200',
            principal_type => xs_acl.ptype_db
        )
    );
    commit; 
end;
/


先ほどのSELECT文を再実行し、PRIVILEGEの再確認を行ないます。connectについてPRIVILEGEGRANTEDになっています。resolveの確認は割愛しますが、同様にGRANTEDになっています。


SQLワークショップSQLコマンドより、REST APIであるversionを呼び出します。手元のPCからORDSのコンテナordsへはlocalhostで接続できますが、データベースのコンテナapexdbからはlocalhostではなく、ORDSのコンテナに割り当てられたIPアドレスを宛先とする必要があります。

コンテナordsに割り当てられたIPアドレスを確認します。

docker inspect --format='{{.NetworkSettings.IPAddress}}' ords

172.17.0.3と確認できました。

% docker inspect --format='{{.NetworkSettings.IPAddress}}' ords


172.17.0.3

ynakakoshi@Ns-MacBook ~ % 


コンテナordsの起動時にIPアドレスが変わると面倒なので、コンテナapexdbと同様に、作成時に--ipオプションを指定して、あらかじめIPアドレスを割り当てておくとよいでしょう。

docker run -d --name ords --ip=172.17.0.3 -v `pwd`/ords_config/:/etc/ords/config/ -p 8181:8181 container-registry.oracle.com/database/ords:latest

SQLコマンドより以下のスクリプトを実行します。
declare
    l_response clob;
begin
    apex_web_service.clear_request_headers();
    l_response := apex_web_service.make_rest_request(
        p_url => 'http://172.17.0.3:8181/ords/apexdev/hr/version/'
        ,p_http_method => 'GET'
    );
    dbms_output.put_line(l_response);
end;
結果に{ "version": "23.1" }が印刷されます。

データベースからREST APIを呼び出せることが確認できました。


OAuthクライアントを作成します。SQL Developer Webに接続します。


詳細を開きパスにapexdevORDSスキーマ属性スキーマ別名として保存した値です)を設定します。ユーザー名パスワードは、APEXのワークスペースの管理者ユーザー(今回はadmin)とそのパスワードを入力します。

SQL Developer WebにスキーマAPEXDEVの権限でサインインします。


REST を開きます。


クライアントを開きます。


OAuthクライアントの作成をクリックします。


クライアント定義のタブを開きます。

付与タイプCLIENT_CREDです。OAuthクライアント名前restuser説明は必須項目なのでRest Userとしました。サポート電子メールも必須項目です。


ロールのタブを開きます。

ロールとしてSQL DeveloperRESTful Servicesを選択します。ORDS Database APIを呼び出しために必要なロールはSQL Developerだけです。RESTful Servicesはサンプルとしてインストールしたoracle.example.hrを使って、OAuthによる保護を確認するために割り当てます。

作成をクリックするとOAuthクライアントが作成されますが、その前にコードの表示オンにしてみます。


ORDSの管理作業はPL/SQLのスクリプトを呼び出して実施することが一般的です。そのため、大体の画面操作で、同等の作業を行なうコードを確認できます。

OAuthクライアントを作成します。


OAuthクライアントが作成されました。

REST APIの認証にクライアントIDクライアント・シークレットを使用するため、これらの値をコピーして安全に保存します。


これらの値を使って、Bearerトークンを取得してみます。

手元のPCより以下のトークンURLに対して、curlコマンドを実行してトークンをリクエストします。ワークスペースのベースURLに/oauth/tokenが続きます。

http://localhost:8181/ords/apexdev/oauth/token
curl http://localhost:8181/ords/apexdev/oauth/token \
-X POST \
-u <クライアントID>:<クライアント・シークレット> \
-d "grant_type=client_credentials"
レスポンスとしてaccess_tokenが返されます。

% curl http://localhost:8181/ords/apexdev/oauth/token \

-X POST \

-u <クライアントID>:<クライアント・シークレット> \

-d "grant_type=client_credentials"

{"access_token":"j2-PVvvomRNWPYclDLsmlw","token_type":"bearer","expires_in":3600}%                  ynakakoshi@Ns-MacBook ~ % 


APEXのワークスペースAPEXDEVにサインインし、ワークショップ・ユーティリティWeb資格証明を開きます。OAuthクライアントのクライアントIDクライアント・シークレットWeb資格証明として保存します。


作成をクリックします。


作成するWeb資格証明の名前静的IDCRED_OAUTH_REST_USERとします。認証タイプOAuth2クライアント資格証明フローを選択し、クライアントIDまたはユーザー名に先ほどコピーしたOAuthクライアントのクライアントIDクライアント・シークレットまたはパスワードクライアント・シークレットを設定します。

以上でWeb資格証明を作成します。


Web資格証明CRED_OAUTH_REST_USERが作成されました。

Web資格証明が正しく作成されたかどうか確認するため、サンプルとして作成されたRESTfulサービスを保護します。

RESTfulサービスを開き、左ペインで権限を選択し権限の作成を実行します。


作成する権限の名前タイトルoracle.example.hrとします。ロールRESTful Servicesモジュールoracle.example.hrを選択します。

以上の設定で権限の作成を実行します。


権限oracle.example.hrが作成されます。


SQLコマンドよりREST APIのversionを呼び出すコードを実行します。実行するコードは同じです。

結果としてUnauthorizedが返されます。


APEX_WEB_SERVICE.MAKE_REST_REQUESTを呼び出す際の引数としてp_credential_static_idCRED_OAUTH_REST_USERp_token_urlhttp://172.17.0.3:8181/ords/apexdev/oauth/tokenを追加します。
declare
    l_response clob;
begin
    apex_web_service.clear_request_headers();
    l_response := apex_web_service.make_rest_request(
        p_url => 'http://172.17.0.3:8181/ords/apexdev/hr/version/'
        ,p_http_method => 'GET'
        ,p_credential_static_id => 'CRED_OAUTH_REST_USER'
        ,p_token_url => 'http://172.17.0.3:8181/ords/apexdev/oauth/token'
    );
    dbms_output.put_line(l_response);
end;
今度は認証に成功し、レスポンスとして{"version": "23.1"}が返されます。

Web資格証明CRED_OAUTH_REST_USERが有効であることが確認できました。


これからORDS Database APIの呼び出しを行ないます。

ORDS Database APIはデフォルトでは有効になっていないため、最初にORDS Database APIを有効にします。通常は以下のコマンドでORDS Database APIを有効にします。

ords config set database.api.enabled true

今回の環境ではコンテナordsで実行するため、以下のコマンドを実行します。

docker exec -it ords ords config set database.api.enabled true

% docker exec -it ords ords config set database.api.enabled true

2024-03-07T10:25:03Z INFO ORDS has not detected the option '--config' and this will be set up to the default directory.


ORDS: Release 23.4 Production on Thu Mar 07 10:25:14 2024


Copyright (c) 2010, 2024, Oracle.


Configuration:

  /etc/ords/config/


No updates required to setting named database.api.enabled in global configuration because the values are the same.

% 


ワークスペースAPEXDEV2に含まれるアプリケーションの一覧を取得してみます。以下のURLを呼び出します。

http://172.17.0.3:8181/ords/apexdev/_/db-api/stable/apex/workspaces/apexdev2/applications/
declare
    l_response clob;
begin
    apex_web_service.clear_request_headers();
    l_response := apex_web_service.make_rest_request(
        p_url => 'http://172.17.0.3:8181/ords/apexdev/_/db-api/stable/apex/workspaces/apexdev2/applications/'
        ,p_http_method => 'GET'
        ,p_credential_static_id => 'CRED_OAUTH_REST_USER'
        ,p_token_url => 'http://172.17.0.3:8181/ords/apexdev/oauth/token'
    );
    dbms_output.put_line(l_response);
end;
レスポンス自体は正常に受け取れますが、ワークスペースAPEXDEV2に作成されているはずのアプリケーション確認用アプリが返ってきません。


このORDS Database APIはスキーマAPEXDEVの権限で実行されています。異なるAPEXワークスペースの情報を参照するには、スキーマはAPEX_ADMINISTRATOR_ROLEを持つ必要があります。

スキーマAPEXDEVにロールAPEX_ADMINISTRATOR_ROLEを割り当てます。ユーザSYSによる接続から実行します。

grant APEX_ADMINISTRATOR_ROLE to apexdev;


再度、ORDS Database APIを呼び出します。今度は確認用アプリが返ってきました。


以上でローカル環境にインストールしたAPEXでORDS Database APIを有効にし、その呼び出しを確認することができました。