Amazon RDS Oracle ウォレットの CA 証明書バンドルを使用して SSL/TLS エンドポイントに接続するにはどうすればよいですか?

所要時間8分
0

Oracle を実行している Amazon Relational Database Services (Amazon RDS) DB インスタンスがあります。Oracle ウォレットを使用して、DB インスタンスから外部 SSL/TLS エンドポイントと安全に通信したいと考えています。

簡単な説明

UTL_HTTP などのユーティリティを使用して、Amazon RDS Oracle DB インスタンスからリモートウェブサーバーのエンドポイントに接続できます。これを安全に行うには、Oracle ウォレットを使用できます。Oracle ウォレットは、ウェブサービスの SSL/TLS エンドポイントにアクセスするために必要なルート証明書と中間証明書を保存するために使用されるコンテナです。

解決方法

Oracle ウォレットを使用してインスタンスから外部 SSL/TLS エンドポイントに接続

1.    ウェブブラウザで、アクセスする URL (ウェブサービスの SSL/TLS エンドポイント) を開きます。

2.    南京錠の記号をクリックして、ブラウザのアドレスバーに証明書の詳細を表示します。ローカルワークステーションのコマンドラインで次のようなコマンドを実行して、証明書の詳細を表示することもできます。

$ openssl s_client -connect status.aws.amazon.com:443
CONNECTED(00000004)
depth=2 C = US, O = Amazon, CN = Amazon Root CA 1
verify return:1
depth=1 C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
verify return:1
depth=0 CN = status.aws.amazon.com
verify return:1
---
Certificate chain
 0 s:CN = status.aws.amazon.com
   i:C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
 1 s:C = US, O = Amazon, OU = Server CA 1B, CN = Amazon
   i:C = US, O = Amazon, CN = Amazon Root CA 1
 2 s:C = US, O = Amazon, CN = Amazon Root CA 1
   i:C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Services Root Certificate Authority - G2
 3 s:C = US, ST = Arizona, L = Scottsdale, O = "Starfield Technologies, Inc.", CN = Starfield Services Root Certificate Authority - G2
   i:C = US, O = "Starfield Technologies, Inc.", OU = Starfield Class 2 Certification Authority
---

注意: status.aws.amazon.com は任意の URL に置き換えてください。

3.    証明書プロバイダーから一覧表示された関連するルート証明書と中間証明書をダウンロードします。スタックトレースから、Amazon ルート CA 1 およびスターフィールドサービスルート認証局 -G2 の証明書が必要であることがわかります。証明書は、Amazon トラストサービスリポジトリからダウンロードできます。証明書が pem 形式で使用できる場合は、それ以上の操作は必要ありません。

4.    証明書が pem 形式でダウンロードできない場合は、証明書を DER/CRT 形式でダウンロードします。次に、ローカルワークステーションのコマンドラインで次のようなコマンドを実行して、ダウンロードした証明書を pem 形式に変換します。

$ openssl x509 -inform der -in AmazonRootCA1.cer -outform pem -out AmazonRootCA1.pem
$ openssl x509 -inform der -in SFSRootCAG2.cer -outform pem -out SFSRootCAG2.pem

5.    orapki ユーティリティを使用してウォレットを作成します。orapki ユーティリティは、該当する Oracle クライアントソフトウェアをインストールするときに使用できます。ウォレットは、ソースデータベース環境で作成する必要があります。Oracle JDeveloper Studio エディションには、orapki ユーティリティも含まれています。ウォレットの作成時に選択するパラメータは異なります。例えば、 auto_login_only パラメータを使用して、開くためにパスワードを必要としない自動ログインウォレット (cwallet.sso) を作成できます。パスワードを使用せずにウォレットを変更または削除することができます。ファイルシステムのアクセス許可が、自動ログインウォレットに必要なセキュリティを提供します。ウォレットの作成に使用できるその他のオプションの詳細は、Oracle ドキュメント「orapki ユーティリティを使用した Oracle ウォレットの管理 」を参照してください。ウォレットを作成するディレクトリを参照します。次に、ローカルワークステーションのコマンドラインで、次のようなコマンドを実行します。

>cd /app/client/wallet
>orapki wallet create -wallet . -auto_login_only

6.    ローカルワークステーションのコマンドラインで次のようなコマンドを実行して、2 つの証明書をウォレットに追加します。

>orapki wallet add -wallet . -trusted_cert -cert AmazonRootCA1.pem -auto_login_only
>orapki wallet add -wallet . -trusted_cert -cert SFSRootCAG2.pem -auto_login_only

7.    ローカルワークステーションのコマンドラインで次のコマンドを実行して、ウォレットの内容を一覧表示します。内容を確認し、証明書が追加されていることを確認します。

>ls -ltrh cwallet.sso
-rw------- 1 user1 Domain Users 2.4K Apr 29 2020 cwallet.sso

>orapki wallet display -wallet .
Oracle PKI Tool Release 18.0.0.0.0 - Production
Version 18.1.0.0.0
Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.

Requested Certificates:
User Certificates:
Trusted Certificates:
Subject:        CN=Amazon Root CA 1,O=Amazon,C=US
Subject:        CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies\, Inc.,L=Scottsdale,ST=Arizona,C=US

8.    マスターユーザーとして SQL*Plus を使用して、Amazon RDS Oracle DB インスタンスに接続します。次のようなコマンドを実行して、UTL_HTTPパッケージを使用するデータベースユーザーに必要な権限を付与します。

SQL> define user='app_user';
SQL>  BEGIN rdsadmin.rdsadmin_util.grant_sys_object('DBA_DIRECTORIES', UPPER('&user')); END;
  2  /
old   1:  BEGIN rdsadmin.rdsadmin_util.grant_sys_object('DBA_DIRECTORIES', UPPER('&user')); END;
new   1:  BEGIN rdsadmin.rdsadmin_util.grant_sys_object('DBA_DIRECTORIES', UPPER('app_user')); END;

PL/SQL procedure successfully completed.

SQL> BEGIN rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('&user')); END;
  2  /
old   1: BEGIN rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('&user')); END;
new   1: BEGIN rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('app_user')); END;

PL/SQL procedure successfully completed.

SQL> BEGIN rdsadmin.rdsadmin_util.grant_sys_object('UTL_FILE', UPPER('&user')); END;
  2  /
old   1: BEGIN rdsadmin.rdsadmin_util.grant_sys_object('UTL_FILE', UPPER('&user')); END;
new   1: BEGIN rdsadmin.rdsadmin_util.grant_sys_object('UTL_FILE', UPPER('app_user')); END;

PL/SQL procedure successfully completed.

9.    RDS DB インスタンスに接続された SQL*Plus セッションで、次のようなコマンドを実行して、ウォレットのディレクトリを作成します。
注意: 各ウォレットを独自のディレクトリに保存するのがベストプラクティスです。

SQL> exec rdsadmin.rdsadmin_util.create_directory('WALLET');

10.    新しい Amazon Simple Storage Service (Amazon S3) バケットを作成するか、既存のバケットを使用してウォレットをアップロードします。AWS コマンドラインインターフェイス (AWS CLI) をインストールして設定している場合は、Oracle ウォレットを作成したクライアントマシンで次のコマンドを実行します。Amazon S3 コンソールからウォレットをアップロードすることもできます。

>aws s3 cp cwallet.sso s3://wallet4321/

注意: AWS CLI コマンドの実行時にエラーが発生した場合は、AWS CLI の最新バージョンを使用していることを確認してください

11.    S3 バケットから RDS DB インスタンスにウォレットをダウンロードします。これは、Amazon S3 統合の有無にかかわらず、実行できます。

Amazon S3 統合を使用して、S3 バケットから RDS インスタンスにウォレットをダウンロード

Amazon S3 統合を使用して S3 バケットからウォレットをダウンロードするには、「 Amazon S3 統合 」を参照してください。

1.    次のコマンドを実行して、S3 バケットから RDS インスタンスディレクトリにウォレットファイルをダウンロードします。

SQL> SELECT rdsadmin.rdsadmin_s3_tasks.download_from_s3(
          p_bucket_name    =>  'wallet4321',
          p_s3_prefix => 'cwallet.sso',
          p_directory_name =>  'WALLET') 
          AS TASK_ID FROM DUAL;   
OUTPUT
1588278782462-32

2.    前のステップのタスク ID を使用してタスクの出力ファイルを表示し、ダウンロードが正常に完了したことを確認して、結果を表示します。

SQL> SELECT text FROM table(rdsadmin.rds_file_util.read_text_file('BDUMP','dbtask-1588278782462-32.log'));

OUTPUT
2020-04-30 20:33:03.452 UTC [INFO ] This task is about to list the Amazon S3 objects for AWS Region us-east-1, bucket name wallet4321, and prefix cwallet.sso.
2020-04-30 20:33:03.526 UTC [INFO ] The task successfully listed the Amazon S3 objects for AWS Region us-east-1, bucket name wallet4321, and prefix cwallet.sso.
2020-04-30 20:33:03.544 UTC [INFO ] This task is about to download the Amazon S3 object or objects in /rdsdbdata/userdirs/01 from bucket name wallet4321 and key cwallet.sso.
2020-04-30 20:33:03.734 UTC [INFO ] The task successfully downloaded the Amazon S3 object or objects from bucket name wallet4321 with key cwallet.sso to the location /rdsdbdata/userdirs/01.
2020-04-30 20:33:03.734 UTC [INFO ] The task finished successfully.

3.    ウォレットが DB インスタンスにダウンロードされていることを確認します。

SQL> select * from table (rdsadmin.rds_file_util.listdir(p_directory => 'WALLET'));
FILENAME  TYPE         FILESIZE   MTIME
------------------------------------------------------------
01/              directory        4096      29-APR-20

cwallet.sso file                  2405     29-APR-20

4.    RDS DB インスタンスに接続された SQL*Plus セッションで、次のようなコマンドを実行して、utl_http トランザクションのウォレットパスを設定します。

SQL>  DECLARE
l_wallet_path all_directories.directory_path%type;
BEGIN
select directory_path into l_wallet_path from all_directories
where upper(directory_name)='WALLET';
utl_http.set_wallet('file:/' || l_wallet_path);
END;
/
PL/SQL procedure successfully completed.

5.    次のようなコマンドを実行して、ウェブサービスホストの DNS 名前解決を確認します。

SQL> SELECT UTL_INADDR.GET_HOST_ADDRESS(host => 'status.aws.amazon.com') FROM DUAL

6.    次のようなコマンドを実行して、Oracle ウォレットを使用してリモートウェブサービス URL を正常に参照します。

SQL> SELECT utl_http.request('https://status.aws.amazon.com/robots.txt') AS ROBOTS_TXT FROM DUAL;

ROBOTS_TXT
--------------------------------------------------------------------------------
User-agent: *
Allow: /

Oracle インスタンスで utl_http を使用する方法の詳細については、「Oracle DB インスタンスでのアウトバウンドネットワークアクセスの設定」を参照してください。

RDS オプショングループで Amazon S3 統合を使用せずに、S3 バケットから RDS インスタンスにウォレットをダウンロード

1.    RDS DB インスタンスに接続された SQL*Plus セッションで、次のようなコマンドを実行し、(定義したユーザーを使用して) Oracle の ACL でアウトバウンドトラフィックを許可します。

SQL> define user='app_user';
SQL> BEGIN DBMS_NETWORK_ACL_ADMIN.CREATE_ACL
     ( acl => 's3.xml', description => 'AWS S3 ACL', principal => UPPER('&user'), is_grant => TRUE, privilege => 'connect');
     COMMIT;
     END;
     /
old   3: ( acl => 's3.xml', description => 'AWS S3 ACL', principal => UPPER('&user'), is_grant => TRUE, privilege => 'connect');
new   3: ( acl => 's3.xml', description => 'AWS S3 ACL', principal => UPPER('app_user'), is_grant => TRUE, privilege => 'connect');

PL/SQL procedure successfully completed.

SQL> BEGIN DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL ( acl => 's3.xml', host => '*.amazonaws.com');
     COMMIT;
     END;
     /
PL/SQL procedure successfully completed.

2.    RDS DB インスタンスに接続された SQL*Plus セッションで、以下の手順を作成します。

SQL> CREATE OR REPLACE PROCEDURE s3_download_presigned_url (
        p_s3_url IN VARCHAR2,
        p_local_filename IN VARCHAR2,
        p_local_directory IN VARCHAR2,
        p_wallet_directory IN VARCHAR2 DEFAULT NULL
    ) AS
-- Local variables
    l_req utl_http.req;
    l_wallet_path VARCHAR2(4000);
    l_fh utl_file.file_type;
    l_resp utl_http.resp;
    l_data raw(32767);
    l_file_size NUMBER;
    l_file_exists BOOLEAN;
    l_block_size BINARY_INTEGER;
    l_http_status NUMBER;
-- User-defined exceptions
    e_https_requires_wallet EXCEPTION;
    e_wallet_dir_invalid EXCEPTION;
    e_http_exception EXCEPTION;
BEGIN
    -- Validate input
    IF (regexp_like(p_s3_url, '^https:', 'i') AND
        p_wallet_directory IS NULL) THEN
        raise e_https_requires_wallet;
    END IF;
    -- Use wallet, if specified
    IF (p_wallet_directory IS NOT NULL) THEN
        BEGIN
                   SELECT directory_path INTO l_wallet_path 
                   FROM dba_directories 
                   WHERE upper(directory_name)= upper(p_wallet_directory);
                   utl_http.set_wallet('file:' || l_wallet_path);
        EXCEPTION
            WHEN NO_DATA_FOUND
                THEN raise e_wallet_dir_invalid;
        END;
    END IF;

    -- Do HTTP request
    BEGIN
        l_req := utl_http.begin_request(p_s3_url, 'GET', 'HTTP/1.1');
                l_fh := utl_file.fopen(p_local_directory, p_local_filename, 'wb', 32767);
        l_resp := utl_http.get_response(l_req);
        -- If we get HTTP error code, write that instead
        l_http_status := l_resp.status_code;
        IF (l_http_status != 200) THEN
            dbms_output.put_line('WARNING: HTTP response '
                || l_http_status
                || ' - ' || l_resp.reason_phrase
                || '. Details in ' || p_local_filename
            );
        END IF;

        -- Loop over response and write to file
        BEGIN
            LOOP
                utl_http.read_raw(l_resp, l_data, 32766);
                utl_file.put_raw(l_fh, l_data, true);
            END LOOP;
        EXCEPTION
            WHEN utl_http.end_of_body THEN

                utl_http.end_response(l_resp);
        END;

        -- Get file attributes to see what we did
        utl_file.fgetattr(
            location => p_local_directory,
            filename => p_local_filename,
            fexists => l_file_exists,
            file_length => l_file_size,
            block_size => l_block_size
        );

        utl_file.fclose(l_fh);
        dbms_output.put_line('wrote ' || l_file_size || ' bytes');
        EXCEPTION
            WHEN OTHERS THEN
                utl_http.end_response(l_resp);
                utl_file.fclose(l_fh);
                dbms_output.put_line(dbms_utility.format_error_stack());
                dbms_output.put_line(dbms_utility.format_error_backtrace());
                raise;
    END;
EXCEPTION

    WHEN e_https_requires_wallet THEN
        dbms_output.put_line('ERROR: HTTPS requires a valid wallet location');
    WHEN e_wallet_dir_invalid THEN
        dbms_output.put_line('ERROR: wallet directory not found');
    WHEN others THEN
        raise;
END s3_download_presigned_url;

3.    次のようなコマンドを実行して、S3 署名付き URL を生成します。
注意: このコマンドを実行するには、クライアントマシンに AWS CLI をインストールして設定する必要があります。署名付き URL は、デフォルトでは 1 時間有効です。詳細については、「事前署名のための AWS CLI リファレンス」を参照してください。

>aws s3 presign s3://wallet4321/cwallet.sso

https://wallet4321.s3.amazonaws.com/cwallet.sso?AWSAccessKeyId=AKIAJWTPIJJA4FAQURFA&Signature=u8ysKQyp4O6ws3Qy5qZak8PfmLE%3D&Expires=1588199836

4.    RDS DB インスタンスに接続された SQL*Plus セッションで、s3_download_presegned_url プロシージャを実行して、S3 バケットから RDS DB インスタンスにウォレットをダウンロードします。プロシージャの入力パラメータを次のように更新してください。
注意: http または https を使用して、S3 バケットから RDS DB インスタンスにウォレットをダウンロードできます。

  • 生成された S3 事前署名付き URL を含む p_s3_url
  • ウォレットファイルの名前を持つ p_local_filename
  • ウォレットを保存する RDS Oracle インスタンス上に作成されたディレクトリの名前を持つ p_local_directory
  • S3_SSL_WALLET を含む p_wallet_directory。このディレクトリは、S3 ウェブサービスの証明書を含むウォレットを保存する RDS Oracle インスタンスによって使用されます。

HTTP により S3 ウェブサービスを使用するには、次のコード例を使用します。

注意: 以前に生成された S3 事前署名付き URL の「http」を「https」に置き換えます。

SQL> SET SERVEROUTPUT ON;
SQL> set define #;
SQL> BEGIN s3_download_presigned_url( 
 p_s3_url=> 'http://wallet4321.s3.amazonaws.com/cwallet.sso?AWSAccessKeyId=AKIAJWTPIJJA4FAQURFA&Signature=u8ysKQyp4O6ws3Qy5qZak8PfmLE%3D&Expires=1588199836',
 p_local_filename => 'cwallet.sso',
 p_local_directory => 'WALLET' 
);
END;
/

HTTPS により S3 ウェブサービスを使用するには、次のコード例を使用します。

注意: RDS インスタンスディレクトリ S3_SSL_WALLET に S3 ウェブサービスウォレットを保存することは、HTTPS を使用するための前提条件です。

SQL> exec rdsadmin.rdsadmin_util.create_directory('S3_SSL_WALLET');
SQL> SET SERVEROUTPUT ON;
SQL> set define #;
SQL> BEGIN s3_download_presigned_url(
      p_s3_url=> 'https://wallet4321.s3.amazonaws.com/cwallet.sso?AWSAccessKeyId=AKIAJWTPIJJA4FAQURFA&Signature=u8ysKQyp4O6ws3Qy5qZak8PfmLE%3D&Expires=1588199836',
      p_local_filename => 'cwallet.sso',
      p_local_directory => 'WALLET',
      p_wallet_directory => 'S3_SSL_WALLET'
     );
     END;
    /

5.    ウォレットが DB インスタンスにダウンロードされていることを確認します。

SQL> select * from table (rdsadmin.rds_file_util.listdir(p_directory => 'WALLET'));
FILENAME         TYPE         FILESIZE   MTIME
------------------------------------------------------------
01/              directory     4096      29-APR-20

cwallet.sso      file          2405      29-APR-20

6.    RDS DB インスタンスに接続された SQL*Plus セッションで、次のようなコマンドを実行して utl_http トランザクションのウォレットパスを設定します。

SQL>  DECLARE
l_wallet_path all_directories.directory_path%type;
BEGIN
select directory_path into l_wallet_path from all_directories
where upper(directory_name)='WALLET';
utl_http.set_wallet('file:/' || l_wallet_path);
END;
/
PL/SQL procedure successfully completed.

7.    次のようなコマンドを実行して、ウェブサービスホストの DNS 名前解決を確認します。

SQL> SELECT UTL_INADDR.GET_HOST_ADDRESS(host => 'status.aws.amazon.com') FROM DUAL

8.    次のようなコマンドを実行して、Oracle ウォレットを使用してリモートウェブサービス URL を正常に参照します。

SQL> SELECT utl_http.request('https://status.aws.amazon.com/robots.txt') AS ROBOTS_TXT FROM DUAL;
ROBOTS_TXT
--------------------------------------------------------------------------------
User-agent: *
Allow: /

一般的なエラー

ORA-28759: ファイルを開くことができません

このエラーは、参照するウォレットが指定した場所にない場合に表示されることがあります。ウォレットファイルの場所を確認するには、次のディレクトリをリストします。

SQL> select directory_name, directory_path from dba_directories where directory_name = 'WALLET';

DIRECTORY_NAME               DIRECTORY_PATH
--------------------------------------------------------------------------------
WALLET                       /rdsdbdata/userdirs/01

ORA-28768: マジックナンバーが悪い

このエラーは、S3 バケットとそのコンテンツが AWS Key Management Service (AWS KMS) を使用して暗号化されている場合に表示されることがあります。このエラーを解決するには、バケットオブジェクトの暗号化を削除します。

ORA-12535: TNS: 動作がタイムアウトしました

このエラーは、次の条件下で表示されることがあります。

  • DB インスタンスがプライベートサブネットにある。
  • ルートテーブルに、インターネットへのルートがない (NAT ゲートウェイまたは NAT インスタンスがない)。

関連情報

Amazon RDS での Oracle

Oracle ウォレットのプロビジョニングと Amazon RDS for Oracle 上の SSL/TLS ベースエンドポイントへのアクセス

Solving utl_file conundrum in Amazon RDS for Oracle

コメントはありません