ラベル AWS の投稿を表示しています。 すべての投稿を表示
ラベル AWS の投稿を表示しています。 すべての投稿を表示

2026年7月17日金曜日

Autonomous AI Databaseのデータベース・ツールを外部認証する - AWS Cognito編

本記事では、AWS Cognitoを外部アイデンティティ・プロバイダーとした設定手順を紹介します。

AWS Cognitoまでは確認しなくて良いかなと思ったのですが、AWS Cognitoのページに「5分未満で無料で開始できます」というボタンがあったので、クリックしました。

データベースの環境などは、これまでの作業環境を踏襲します。GCPの構成を確認した環境をそのまま使用します。DBMS_CLOUD_ADMIN.ENABLE_EXTERNAL_AUTHENTICATIONで設定する環境は、Oracle IAMかMicrosoft Entra IDかのどちらかを選択しますが、DBMS_CLOUD_FUNCTION_ADMIN.CREATE_IDPで作成するIDPは、同時に複数のIDPを作成できます。


AWS Cognitoの構成



アプリケーションを定義します。

アプリケーションタイプとして従来のウェブアプリケーションを選択します。アプリケーションの名前SALESADBとします。

最低限のオプションを設定します。

サインイン識別子のオプションメールアドレスチェックします。また、サインアップのための必須属性としてemailを選択します。

リターンURLとして以下の形式のリダイレクトURIを設定します。

https://[パブリック・アクセスURLのホスト部]/adb/auth/v1/connect/aws/callback

以上でユーザーディレクトリを作成します。


ユーザープールが作成されます。作成されたユーザープールを開きます。


OpenID Connect設定URLをコピーします。この値はDBMS_CLOUD_FUNCTION_ADMIN.CREATE_IDPの引数discovery_urlの値になります。


サイド・メニューのアプリケーションからアプリケーションクライアントを開き、作成済みのアプリケーションクライアントSALESADBを開きます。


クライアントIDクライアントシークレットをコピーします。これらも、DBMS_CLOUD_FUNCTION_ADMIN.CREATE_IDPの引数の値になります。


ユーザー管理ユーザーを開き、接続に使用するユーザーを作成します。

メールアドレスとパスワードでサインインできるように、ユーザーを作成しています。


グループとしてsales_dbusersを作成します。説明に、データベースに接続できるユーザーと書きました。

公式ドキュメントのProvider Specific Noteには、shared-role mappings with AWS_ROLEと記述されているのですが、実際にAWS_ROLEとして指定するのは、ここで作成しているグループ名でした。ロールを作成して同様にユーザー認証されるかどうかは、確認していません。


グループsales_dbusersに、先ほど作成したテスト用のユーザーを追加します。


以上で、AWS CognitoにOAuthクライアントが作成されました。



データベース・ツールの外部認証の構成



GCPでの構成から、作業を継続している前提です。

IDPとしてAWS Cognitoを作成します。
BEGIN
   DBMS_CLOUD_FUNCTION_ADMIN.CREATE_IDP(
      idp_name       => 'AWS',
      client_id      => '<client-id>',
      client_secret  => '<client-secret>',
      params         => JSON_OBJECT(
                           'discovery_url' VALUE
                           'https://cognito-idp.<region>.amazonaws.com/<user-pool-id>/.well-known/openid-configuration'
                           ));
END;
/

SQL> BEGIN

  2     DBMS_CLOUD_FUNCTION_ADMIN.CREATE_IDP(

  3        idp_name       => 'AWS',

  4        client_id      => '**********************',

  5        client_secret  => '**************************************',

  6        params         => JSON_OBJECT(

  7                             'discovery_url' VALUE

  8                             'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_***************/.well-known/openid-configuration'

  9                             ));

 10  END;

 11* /


PL/SQLプロシージャが正常に完了しました。


SQL>


データベース・ユーザーWKSP_APEXDEVに紐づけられている、グローバル・ユーザーの定義を更新します。

alter user wksp_apexdev identified globally as 'AWS_ROLE=sales_dbusers';

SQL> alter user wksp_apexdev identified globally as 'AWS_ROLE=sales_dbusers';


User WKSP_APEXDEVが変更されました。


SQL> 


初回の構成であれば、ユーザーWSKP_APEXDEVへの権限の付与、DBMS_CLOUD_ADMIN.ENABLE_EXTERNAL_AUTHENTICATIONおよびORDS_ADMIN.ENABLE_SCHEMAも実行します。

以上で、データベース・ツールの認証にAWS Cognitoを使用できるようになりました。


データベース・ツールへの接続



Autonomous AI Databaseに接続し、使用するツールとしてSQL Developer Webを選択します。


SSOでサインインをクリックします。


外部アイデンティティ・プロバイダーとしてAWSを選択します。


AWS Cognitoのサインイン画面が表示されます。テスト用に作成したユーザーのメールアドレスを入力し、Nextをクリックします。


パスワードを入力し、Continueをクリックします。


HTTPのステータス・コードとして404 Not Foundが返されました。これは、ORDS別名として設定したapexdevではなく、スキーマ名がURLに含まれるために発生しています。

ブラウザに表示されているURLの/ords/wksp_apexdev/_sdw/の部分を/ords/apexdev/_sdw/に変更して、URLにアクセスします。

URLを変更すると、データベース・アクションに接続されます。


AWS Cognitoで認証したユーザーにて、データベース・ツールに接続できました。



Oracle APEXへの接続




ワークスペースAPEXDEVが作成済みとします。AWS Cognitoで作成したユーザーを管理者ユーザーとして追加します。

APEX_UTIL.SET_WORKSPACEを呼び出し、対象のワークスペースに切り替えてから、APEX_UTIL.CREATE_USERを呼び出します。
begin
apex_util.set_workspace('APEXDEV');
apex_util.create_user(
    p_user_name        => upper('<AWS Cognitoユーザー>'),
    p_web_password     => '<パスワード>',
    p_developer_privs  => 'ADMIN:CREATE:DATA_LOADER:EDIT:HELP:MONITOR:SQL',
    p_email_address    => '<AWS Cognitoユーザー>',
    p_default_schema   => 'WKSP_APEXDEV',
    p_change_password_on_first_use => 'N'
);
end;
/
commit;
exit
以上で、APEXワークスペースと管理者ユーザーの追加ができました。

APEXへの接続を確認します。

ORDSのランディング・ページより、Oracle APEX実行します。


AWSを選択します。


AWS Cognitoでサインインします。


AWS Cognitoでサインインしたユーザーに、ワークスペースAPEXDEVが紐づいています。

APEXDEVを選択します。


APEXにサインインできました。


以上で、外部アイデンティ・プロバイダーで認証したユーザーで、Oracle APEXの開発ツールに接続できました。

今回の記事は以上になります。


2023年12月20日水曜日

Amazon Bedrock Agents APIのリクエストに署名バージョン4の署名を付ける

Oracle APEXのアプリケーションからAWSのREST APIを呼び出すには、リクエストに署名を付加する必要があります。これはAmazon Bedrock Agents APIについても同様です。

AWSからは署名バージョン4のリファレンスとして、以下のページが公開されています。英語ですし内容も難しいので、これを読んで署名処理を実装するのはかなり難しいと思います。

Signing AWS API requestsRequest signature examples
Troubleshoot signed requests for AWS APIs

日本語では、以下の説明がわかりやすかったです。

AWS の API を理解しよう !
中級編 ~ リクエストの署名や CLI/SDK の中身を覗いてみる

いちから署名処理を実装するのは大変なので、Amazon S3にアクセスするために書かれたパッケージより、署名処理の部分を流用することにしました。

plsql-aws-s3

パッケージAWS4_S3_PKGに、Amazon S3を操作するファンクションやプロシージャが実装されています。このパッケージを元に、署名生成に使われているプライベート・ファンクションを残したパッケージAWS4_REST_PKGを作成しました。これらのファンクションでS3に決め打ちになっている部分を、bedrockを呼び出せるように改変しています。

S3を操作するためのファンクションはすべて削除しています。その上で、署名バージョン4を生成し、HTTPのリクエスト・ヘッダーに設定するファンクションset_authorization_headersを新設しています。パッケージAWS4_REST_PKGのパブリックなファンクションはこれだけです。ファンクションset_authorization_headersではREST APIの呼び出しは行わず、apex_web_service.set_request_headersを呼び出して、署名バージョン4による署名を含んだAuthorizationヘッダーおよびその他いくつかの関連したヘッダーの設定だけを行います。

aws4_rest_pkg.set_authorization_headresを呼び出した後に、apex_web_service.make_rest_requestを呼び出すことによって、署名が付いたREST APIを発行します。

パッケージAWS4_REST_PKG本体のコードは記事の末尾に添付します。

パッケージAWS4_REST_PKGをインストールした後に実施した、動作確認の作業を記述します。以下の記事と同じ手順で、AWSのIAMユーザーとしてoracletestuserが作成済みで、アクセスキーシークレットアクセスキーが作成済みとします。

Oracle Database 23c FreeにDBMS_CLOUDパッケージを入れてAmazon S3にアクセスする

AWSコンソールよりBedrockのページを開きます。今回はAgents APIを呼び出すことを想定しています。Agentsが使えるリージョンは限られているようなので、メニューにAgentsが表示されない場合は、リージョンを切り替える必要があります。以下の作業はバージニア北部(us-east-1)で実施しています。

Agentsから使える基盤モデルは、現時点ではAnthropicに限られているようです。


Request model accessをクリックしてみます。

AnthropicClaudeおよびClaude Instantについては、Access statusUse case details requiredとなっています。今回はAgentsから実際に基盤モデルを呼び出すのは(お金もかかるので)やめて、署名バージョン4が正しく生成できていることだけを確認することにします。


Agentsのページを開き、新しくAgentを作成します。Create Agentをクリックします。


Agent nameMyAgentとしました。Agent description - optionalには「My First Bedrock Agent.」と記述しています。それ以外はデフォルトのままです。

今回は署名が付与されたREST APIの認証が通ればよいので、Bedrock Agent自体の設定は最低限にします。BedrockのAgentsの詳細については、他の資料にあたっていただくようお願いします。

Nextをクリックします。


基盤モデルの選択画面に移ります。選択できるモデルはAnthropicのClaude Instant V1またはClaude V2です。2023年12月20日時点では、Claude V2.1はComing Soonです。どちらのモデルを選択しても、Claudeは使用をリクエストしないと呼び出せません。

とりあえずClaude Instant V1を選択し、Instructions for the Agentとして「あなたは日本語を話す親切なエージェントです。丁寧な言葉遣いで回答し差別的な用語は使いません。」と記述して、Nextをクリックします。


Action groupsの追加画面が開きます。OpenAIでのFunction Callingと同等の機能と考えて良いかと思います。OpenAIのFunction Callingとは異なり、AgentはActionとして設定したLambdaファンクションの呼び出しまでを実施するようです。

Action groupsとして何も設定せず、Nextをクリックします。


Knowledge baseの追加画面が開きます。OpenAIでのRetrievalに当たる機能かと思います。Amazon S3に保存してあるドキュメントからベクトル埋め込み(embeddings)を生成しOpenSearchやPineconeに保存して、RAG(Retrieval-Augmented Generation)を実行する機能のようです。

Knowledge baseも何も設定せず、Nextをクリックします。


設定内容を確認し、Create Agentをクリックします。


AgentとしてMyAgentが作成されます。これからポリシーを作成するにあたって、アカウントIDAgent IDを使います。そのため、Agent ARNをコピーしておきます。


Identity and Access Management (IAM)のページのポリシーを開き、ポリシーの作成をクリックします。


ポリシーエディタとしてJSONを選択し、JSONでポリシーを記述します。作成されているAgentを一覧するListAgentsと、Agentを指定して情報を取得するGetAgentの呼び出し、および、Agentを指定してAliasをアップデートするUpdateAgentAliasとAgentに処理を依頼するInvokeAgentを許可します。

[アカウントID]の部分はアカウントIDである12桁の数値に置き換えます。[Agent ID]AgentのIDに置き変えます。Agentとして未デプロイのWorking draftを指定するため、Agent AliasとしてTSTALIASIDを指定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "BedrockConsole",
            "Effect": "Allow",
            "Action": [
                "bedrock:ListAgents",
                "bedrock:GetAgent"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AgentAliasSid",
            "Effect": "Allow",
            "Action": [
                "bedrock:UpdateAgentAlias",
                "bedrock:InvokeAgent"
            ],
            "Resource": [
                "arn:aws:bedrock:us-east-1:[アカウントID]:agent-alias/[Agent ID]/TSTALIASID"
            ]
        }
    ]
}
次へ進みます。


ポリシー名OracleBedrockAgentPolicy_MyAgentと記述します。

ポリシーの作成をクリックすると、Bedrock Agentの呼び出しを許可するポリシーが作成されます。


作成済みのユーザーoracletestuserを開き、許可タブより許可を追加を実行します。


許可を追加の画面でポリシーを直接アタッチするを選択します。アタッチするポリシーとして先ほど作成したポリシーOracleBedrockAgentPolicy_MyAgentを検索し、チェックを入れます。

次へ進みます。


確認画面で許可を追加をクリックします。


Bedrock Agentの作成とアクセスの許可が完了しました。ユーザーoracletestuserのアクセスキーとシークレットアクセスキーは生成済みという前提なので、これでAWS側での準備は完了です。

これからOracle APEXのSQLコマンドからBedrock AgentのREST APIを呼び出してみます。

ListAgentsを呼び出してみます。以下のコードを実行します。


レスポンスとしてagentSummariesが返されました。REST APIに署名が正しく付けられているようです。


GetAgentを呼び出してみます。以下のコードを実行します。



InvokeAgentを呼び出してみます。


dependencyFailedExceptionが返されます。messageは"Access denied when calling Bedrock. Check your request permissions and retry the request."となっています。これはClaude Instance V1へのアクセスをリクエストしていないためだと思われます。

HTTPのステータス・コードは200が返されているため、署名は正しく生成されていると言えます。


印刷されたレスポンスを見ると、一筋縄では行かなそうなフォーマットでレスポンスが返されています。InvokeAgentのリファレンスのResponse SyntaxはJSONになっています。


Amazon Bedrock Agents APIを呼び出すための署名バージョン4の生成について、パッケージの作成とその動作確認については以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。

補足

パッケージDBMS_CLOUDにSEND_REQUESTというファンクション(およびプロシージャ)があります。開発元に確認してはいませんが、credentialScopeがs3に固定されているように見えます。credentialScopeを指定する引数はありませんし、s3以外のサービスを呼び出すとAuthentication Failedが返されます。




2023年12月19日火曜日

ARNを使ったクリデンシャルを作成してAPEXのワークスペースからAWS S3のバケットにアクセスする

Oracle Autonomous Database(Always Freeを使います)に、AWS IAMで作成したロールのARNs(Amazon Resource Names)を使ったクリデンシャルを作成して、AWS S3にアクセスしてみます。

S3のバケットは、以下の記事に書かれている手順で作成したmyoraclefreebucketを使います。ポリシーも同じ記事に手順があるポリシーOracleFreeS3Policyを使います。

Oracle Database 23c FreeにDBMS_CLOUDパッケージを入れてAmazon S3にアクセスする

Autonomous DatabaseにユーザーADMINでアクセスし、SQL Developer WebSQLワークシートを開きます。


APEXのワークスペースはAPEXDEV、ワークスペース・スキーマはWKSP_APEXDEVとして作成済みとします。

ワークスペース・スキーマWKSP_APEXDEVで、AWSのARNを使った認証を有効にします。
begin
    dbms_cloud_admin.enable_principal_auth(
        provider => 'AWS'
        ,username => 'WKSP_APEXDEV'
    );
end;


ビューCLOUD_INTEGRATIONSを検索し、AWSのIAMで作成するロールにアカウントIDとして設定する値を取得します。
select param_value from cloud_integrations where param_name = 'aws_user_arn'


APEXからの利用なので、AWSのIAMのロールの外部IDデータベースのOCIDを設定することにします。未確認ですが、テナントのOCIDコンパートメントのOCID外部IDとすることもできるようです。

Autonomous Databaseの情報ページを開き、OCIDコピーします。


AWSコンソールを開きIAMロールより、ロールを作成します。


信頼されたエンティティタイプとしてAWSアカウントを選択します。AWSアカウントとして別のAWSアカウントを選択し、アカウントIDにビューCLOUD_INTEGRATIONSPARAM_NAMEaws_user_arnPARAM_VALUEとして得られた値の12桁の数値の部分を設定します。

オプション外部IDを要求するチェックを入れ、外部IDとしてデータベースのOCIDを設定します。

次へ進みます。


許可ポリシーとしてOracleFreeS3Policyを検索し、チェックを入れます。

次へ進みます。


ロール名としてOracleAPEXRole説明としてRole for Oracle APEX.と入力して、ロールを作成します。


ロールOracleAPEXRoleが作成されます。ロールのARNを取得するため、作成されたロールを表示します。


作成されたロールOracleAPEXRoleARNをコピーします。


以上でAWS側の設定は完了です。

Autonomous Databaseに戻ります。

パッケージDBMS_CLOUDの実行権限を、APEXのワークスペース・スキーマWKSP_APEXDEVに与えます。デフォルトの状態では、APEXのワークスペース・スキーマはDBMS_CLOUDの実行権限を持っていません。
grant execute on dbms_cloud to wksp_apexdev;

これからは、APEXのSQLコマンドから作業を行います。

AWSのロールのARNを使ったクリデンシャルをaws_role_arnという名前で作成します。
begin
    dbms_cloud.create_credential(
        credential_name => 'aws_role_arn'
        ,params => json_object(
            'aws_role_arn' value 'ロールOracleAPEXRoleのARN'
            ,'external_id_type' value 'database_ocid'
        )
    );
end;
作成が完了するまでにかなりの時間(10秒前後)かかります。


ビューUSER_CREDENTIALSを検索し、作成されたクリデンシャルを確認します。

select * from user_credentials


S3のバケットを操作し、クリデンシャルが正しく作成されたことを確認します。

これからの手順は、以前の記事と同じでクリデンシャルだけが異なります。

内容にmy first uploadと記載したファイルtest.txtを、S3のバケットにアップロードします。
declare
    l_resp dbms_cloud_types.resp;
    l_blob blob;
    l_clob clob;
begin
    l_clob := 'my first upload';
    l_blob := apex_util.clob_to_blob(l_clob);
    l_resp := dbms_cloud.send_request(
        credential_name => 'aws_role_arn'
        ,uri => 'https://s3.us-east-1.amazonaws.com/myoraclefreebucket/test.txt'
        ,method => 'PUT'
        ,body => l_blob
    );
end;

バケットの内容をリストします。test.txtがアップロードされていることが確認できます。
select * from dbms_cloud.list_objects(
    credential_name => 'aws_role_arn'
,location_uri => 'https://s3.us-east-1.amazonaws.com/myoraclefreebucket' )

ファイルtest.txtを取得します。ファイルの内容がmy first uploadとして表示されます。
declare
    l_resp dbms_cloud_types.resp;
    l_clob clob;
begin
    l_resp := dbms_cloud.send_request(
        credential_name => 'aws_role_arn'
,uri => 'https://s3.us-east-1.amazonaws.com/myoraclefreebucket/test.txt' ,method => 'GET' ); l_clob := dbms_cloud.get_response_text( resp => l_resp ); dbms_output.put_line(l_clob); end;


ファイルtest.txtを削除します。
begin
    dbms_cloud.send_request(
        credential_name => 'aws_role_arn'
,uri => 'https://s3.us-east-1.amazonaws.com/myoraclefreebucket/test.txt' ,method => 'DELETE' ); end;

再度、バケット内のファイルをリストします。データが見つかりませんと返されます。


今回の記事は以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。