

# 証明書と Oracle ウォレットを使用した、UTL\$1HTTP アクセスの設定
<a name="Oracle.Concepts.ONA"></a>

Amazon RDS は RDS for Oracle DB インスタンスでのアウトバウンドネットワークアクセスをサポートします。DB インスタンスをネットワークに接続するには、次の PL/SQL パッケージを使用できます。

`UTL_HTTP`  
このパッケージでは、SQL および PL/SQL から HTTP 呼び出しを実行します。HTTP 経由でインターネット上のデータにアクセスするために使用できます。詳細については、Oracle ドキュメントの「[UTL\$1MAIL](https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/UTL_HTTP.html#GUID-A85D2D1F-90FC-45F1-967F-34368A23C9BB)」を参照してください。

`UTL_TCP`  
このパッケージは、PL/SQL で TCP/IP クライアント側アクセス機能を提供します。このパッケージは、インターネットプロトコルと E メールを使用する PL/SQL アプリケーションに役立ちます。詳細については、Oracle ドキュメントの「[UTL\$1TCP](https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/UTL_TCP.html#GUID-348AFFE8-78B2-4217-AE73-384F46A1D292)」を参照してください。

`UTL_SMTP`  
このパッケージは、SMTP コマンドへのインターフェイスを提供します。これにより、クライアントが E メールを SMTP サーバーにディスパッチできるようにします。詳細については、Oracle ドキュメントの「[UTL\$1SMTP](https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/UTL_SMTP.html#GUID-F0065C52-D618-4F8A-A361-7B742D44C520)」を参照してください。

次のタスクを完了すると、`UTL_HTTP.REQUEST` を設定できます。これにより、SSL ハンドシェイク中にクライアント認証の証明書を要求するウェブサイトを操作できます。また Oracle ウォレットの生成コマンドや、`DBMS_NETWORK_ACL_ADMIN.APPEND_WALLET_ACE` の手順を修正して、ウェブサイトへの `UTL_HTTP` アクセスに使用するパスワード認証を設定することもできます。詳細については、Oracle Database のドキュメントの「[DBMS\$1NETWORK\$1ACL\$1ADMIN](https://docs.oracle.com/en/database/oracle/oracle-database/21/arpls/DBMS_NETWORK_ACL_ADMIN.html)」を参照してください。

**注記**  
`UTL_SMTP` に合わせ次のタスクを変更して、SSL/TLS 経由でメールを送信できるようにします ([Amazon Simple Email Service](https://aws.amazon.com/ses/) を含む)。

**Topics**
+ [UTL\$1HTTP アクセスを設定する際の考慮事項](#utl_http-considerations)
+ [ステップ 1: ウェブサイトのルート証明書を取得する](#website-root-certificate)
+ [ステップ 2: Oracle ウォレットを作成する](#create-oracle-wallet)
+ [ステップ 3: RDS for Oracle インスタンスに、Oracle ウォレットをダウンロードする](#upload-wallet-to-instance)
+ [ステップ 4: ユーザーに Oracle ウォレットへのアクセス許可を付与する](#config-oracle-wallet-user)
+ [ステップ 5: DB インスタンスからウェブサイトへのアクセスを設定する](#config-website-access)
+ [ステップ 6: DB インスタンスからウェブサイトへの接続をテストする](#test_utl_http)

## UTL\$1HTTP アクセスを設定する際の考慮事項
<a name="utl_http-considerations"></a>

アクセスを設定する前に、以下を考慮してください。
+ UTL\$1MAIL オプションで SMTP を使用することができます。詳細については、「[Oracle UTL\$1MAIL](Oracle.Options.UTLMAIL.md)」を参照してください。
+ リモートホストのドメインネームサーバー (DNS) の名は、以下のいずれかです: 
  + パブリックに解決可能。
  + Amazon RDS DB インスタンスのエンドポイント。
  + 独自のDNS サーバーを介して解決可能。詳細については、「[カスタム DNS サーバーのセットアップ](Appendix.Oracle.CommonDBATasks.System.md#Appendix.Oracle.CommonDBATasks.CustomDNS)」を参照してください。
  + 同じ VPC またはピアリング接続先 VPC の Amazon EC2 インスタンスのプライベート DNS 名。この場合、名前がカスタム DNS サーバーを介して解決可能であることを確認してください。また、VPC 設定の `enableDnsSupport` 属性を有効にし、VPC ピア接続の DNS 解決サポートを有効にすることで Amazon が提供する DNS を使用することもできます。詳細については、「[VPC の DNS サポート](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#vpc-dns-support)」および「[VPC ピア接続の変更](https://docs.aws.amazon.com/vpc/latest/peering/working-with-vpc-peering.html#modify-peering-connections)」を参照してください。
  + リモート SSL/TLS リソースに安全に接続するには、カスタマイズされた Oracle ウォレット を作成し、アップロードすることをお勧めします。Amazon S3 を Amazon RDS for Oracle 機能と統合することで、Amazon S3 から Oracle DB インスタンスにウォレットをダウンロードします。Oracle 用の Amazon S3 の統合については、「[「Amazon S3 統合」](oracle-s3-integration.md)」を参照してください。
+ Oracle SSL オプションがインスタンスごとに構成されている場合は、SSL/TLS エンドポイントを介して Oracle DB インスタンス間にデータベースリンクを確立することができます。必要な設定はこれだけです。詳細については、「[Oracle Secure Sockets Layer](Appendix.Oracle.Options.SSL.md)」を参照してください。

## ステップ 1: ウェブサイトのルート証明書を取得する
<a name="website-root-certificate"></a>

RDS for Oracle DB インスタンスがウェブサイトへのセキュアな接続を確立するには、ルート CA 証明書を追加します。Amazon RDS はルート証明書を使用して、Oracle ウォレットにウェブサイトの証明書を署名します。

ルート証明書は、さまざまな方法で取得できます。例えば、次のオペレーションを実行できます。

1. ウェブサーバーを使用して、証明書で保護されたウェブサイトにアクセスします。

1. 署名に使われたルート証明書をダウンロードします。

AWS のサービスの場合、ルート証明書は通常、[Amazon Trust Services リポジトリ](https://www.amazontrust.com/repository/)にあります。

## ステップ 2: Oracle ウォレットを作成する
<a name="create-oracle-wallet"></a>

ウェブサーバー証明書とクライアント認証証明書の両方を含む Oracle ウォレットを作成します。RDS Oracle インスタンスは、ウェブサーバー証明書を使用して、ウェブサイトへの安全な接続を確立します。ウェブサイトでは、Oracle のデータベースユーザーを認証するために、クライアント証明書が必要です。

認証にクライアント証明書を使用せずに、セキュアな接続を構成したい場合があります。この場合、次の手順で Java キーストアのステップを省略できます。

**Oracle ウォレットを作成するには**

1. ルート証明書とクライアント証明書を 1 つのディレクトリに配置してから、このディレクトリに移動します。

1. .p12 クライアント証明書を、Java キーストアに変換します。
**注記**  
認証にクライアント証明書を使用していない場合は、このステップを省略できます。

   次の例では、*client\$1certificate.p12* という名前のクライアント証明書を、*client\$1keystore.jks* という名前の Java キーストアに変換します。その後、キーストアは Oracle ウォレットに入ります。キーストアのパスワードは *P12PASSWORD* です。

   ```
   orapki wallet pkcs12_to_jks -wallet ./client_certificate.p12 -jksKeyStoreLoc ./client_keystore.jks -jksKeyStorepwd P12PASSWORD
   ```

1. 証明書のディレクトリとは別に、Oracle ウォレット用のディレクトリを作成します。

   例えば、次の例では `/tmp/wallet` ディレクトリを作成します。

   ```
   mkdir -p /tmp/wallet
   ```

1. ウォレットディレクトリに、Oracle ウォレットを作成します。

   次の例では、Oracle ウォレット パスワードを *P12PASSWORD* に設定します。これは、前のステップで Java キーストアで使用したのと同じパスワードです。同じパスワードを使用すると便利ですが、必須ではありません。`-auto_login` パラメータが自動ログイン機能をオンにするため、アクセスするたびにパスワードを指定する必要はありません。
**注記**  
セキュリティ上のベストプラクティスとして、ここに示されているプロンプト以外のパスワードを指定してください。

   ```
   orapki wallet create -wallet /tmp/wallet -pwd P12PASSWORD -auto_login
   ```

1. Java キーストアを、Oracle ウォレットに追加します。
**注記**  
認証にクライアント証明書を使用していない場合は、このステップを省略できます。

   次の例では、*/tmp/wallet* という Oracle ウォレットに、*client\$1keystore.jks* キーストアを追加します。この例では、Java キーストアと Oracle ウォレットに、同じパスワードを指定します。

   ```
   orapki wallet jks_to_pkcs12 -wallet /tmp/wallet -pwd P12PASSWORD -keystore ./client_keystore.jks -jkspwd P12PASSWORD
   ```

1. Oracle ウォレットに、対象のウェブサイトのルート証明書を追加します。

   次の例では、*Root\$1CA.cer* という名前の証明書を追加します。

   ```
   orapki wallet add -wallet /tmp/wallet -trusted_cert -cert ./Root_CA.cer -pwd P12PASSWORD
   ```

1. 中間証明書を追加します。

   次の例では、*Intermediate.cer* という名前の証明書を追加します。中間証明書をすべてロードするまで、この手順を必要な回数繰り返します。

   ```
   orapki wallet add -wallet /tmp/wallet -trusted_cert -cert ./Intermediate.cer -pwd P12PASSWORD
   ```

1. 新しく作成した Oracle ウォレットに、必要な証明書があることを確認します。

   ```
   orapki wallet display -wallet /tmp/wallet -pwd P12PASSWORD
   ```

## ステップ 3: RDS for Oracle インスタンスに、Oracle ウォレットをダウンロードする
<a name="upload-wallet-to-instance"></a>

このステップでは、まず Oracle ウォレットを Amazon S3 にアップロードし、次に Amazon S3 から RDS for Oracle インスタンスにウォレットをダウンロードします。

**RDS for Oracle DB インスタンスに Oracle ウォレットをダウンロードするには**

1. Oracle との Amazon S3 統合の前提条件を満たしたら、`S3_INTEGRATION` オプションを Oracle DB インスタンスに追加します。使用している Amazon S3 バケットへのアクセス権が、オプションの IAM ルールにあることを確認します。

   詳細については、「[「Amazon S3 統合」](oracle-s3-integration.md)」を参照してください。

1. マスターユーザーとして DB インスタンスにログインし、Oracle ウォレットを保持しておく Oracle ディレクトリを作成します。

   次の例では、*WALLET\$1DIR* という名前で Oracle のディレクトリを作成しています。

   ```
   EXEC rdsadmin.rdsadmin_util.create_directory('WALLET_DIR');
   ```

   詳細については、「[主要データストレージ領域でのディレクトリの作成と削除](Appendix.Oracle.CommonDBATasks.Misc.md#Appendix.Oracle.CommonDBATasks.NewDirectories)」を参照してください。

1. 作成した Oracle ウォレットを Amazon S3 バケットにアップロードします。

   サポートされているアップロード方法は、いずれも使用できます。

1. Oracle ウォレットを再度アップロードする場合は、既存のウォレットを削除します。それ以外の場合は、次のステップに進みます。

   次の例では、*cwallet.sso* という名前の、既存のウォレットを削除します。

   ```
   EXEC UTL_FILE.FREMOVE ('WALLET_DIR','cwallet.sso');
   ```

1. Amazon S3 バケットから Oracle DB インスタンスに Oracle ウォレットをダウンロードします。

   次の例では、*cwallet.sso* という名前のウォレットを、*my\$1s3\$1bucket* という名前の Amazon S3 バケットから、*WALLET\$1DIR* という名前の DB インスタンスディレクトリにダウンロードしています。

   ```
   SELECT rdsadmin.rdsadmin_s3_tasks.download_from_s3(
         p_bucket_name    =>  'my_s3_bucket', 
         p_s3_prefix      =>  'cwallet.sso', 
         p_directory_name =>  'WALLET_DIR') 
      AS TASK_ID FROM DUAL;
   ```

1. (オプション) パスワードで保護された Oracle ウォレットをダウンロードします。

   このウォレットは、ウォレットを使用するたびにパスワードを要求する場合にのみ、ダウンロードしてください。次の例では、パスワードで保護された *ewallet.p12* ウォレットをダウンロードしています。

   ```
   SELECT rdsadmin.rdsadmin_s3_tasks.download_from_s3(
         p_bucket_name    =>  'my_s3_bucket', 
         p_s3_prefix      =>  'ewallet.p12', 
         p_directory_name =>  'WALLET_DIR') 
      AS TASK_ID FROM DUAL;
   ```

1. DB タスクのステータスを確認します。

   次の例では、前のステップで返されたタスク ID を、*dbtask-1234567890123-4567.log* に代入します。

   ```
   SELECT TEXT FROM TABLE(rdsadmin.rds_file_util.read_text_file('BDUMP','dbtask-1234567890123-4567.log'));
   ```

1. Oracle ウォレットの保存に使用している、ディレクトリの内容を確認します。

   ```
   SELECT * FROM TABLE(rdsadmin.rds_file_util.listdir(p_directory => 'WALLET_DIR'));
   ```

   詳細については、「[DB インスタンスディレクトリ内のファイルのリスト化](Appendix.Oracle.CommonDBATasks.Misc.md#Appendix.Oracle.CommonDBATasks.ListDirectories)」を参照してください。

## ステップ 4: ユーザーに Oracle ウォレットへのアクセス許可を付与する
<a name="config-oracle-wallet-user"></a>

データベースのユーザーを新しく作成するか、既存のユーザーを設定できます。いずれの場合も、証明書を使用したセキュアな接続や、クライアント認証のために、Oracle ウォレットにアクセスするようにユーザーを設定する必要があります。

**Oracle ウォレットのユーザーアクセス許可を付与するには**

1. RDS for Oracle DB インスタンスに、マスターユーザーとしてログインします。

1. 既存のデータベースユーザーを設定しない場合は、新しいユーザーを作成します。それ以外の場合は、次のステップに進みます。

   次の例では、*my-user* という名前のデータベースユーザーを作成します。

   ```
   CREATE USER my-user IDENTIFIED BY my-user-pwd;
   GRANT CONNECT TO my-user;
   ```

1. データベースユーザーに、Oracle ウォレットのあるディレクトリに対するアクセス許可を付与します。

   次の例では、*my-user* ユーザーに対して、*WALLET\$1DIR* ディレクトリへの読み取りアクセス権限を付与します。

   ```
   GRANT READ ON DIRECTORY WALLET_DIR TO my-user;
   ```

1. データベースユーザーに対して、`UTL_HTTP` パッケージを使用するアクセス許可を付与します。

   次の PL/SQL プログラムは、*my-user* ユーザーに対して、`UTL_HTTP` へのアクセス許可を付与します。

   ```
   BEGIN 
     rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('my-user')); 
     END;
   /
   ```

1. データベースユーザーに対して、`UTL_FILE` パッケージを使用するアクセス許可を付与します。

   次の PL/SQL プログラムは、*my-user* ユーザーに対して、`UTL_FILE` へのアクセス許可を付与します。

   ```
   BEGIN 
     rdsadmin.rdsadmin_util.grant_sys_object('UTL_FILE', UPPER('my-user')); 
     END;
   /
   ```

## ステップ 5: DB インスタンスからウェブサイトへのアクセスを設定する
<a name="config-website-access"></a>

このステップでは、`UTL_HTTP` やアップロードした Oracle ウォレット、クライアント証明書を使用して、対象のウェブサイトに接続できるように、Oracle データベースユーザーを設定します。詳細については、Oracle Database のドキュメントの「[Configuring Access Control to an Oracle Wallet](https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/managing-fine-grained-access-in-pl-sql-packages-and-types.html#GUID-0BCB5925-A40F-4507-95F9-5DA4A1919EBD)」(Oracle Wallet に対するアクセス制御の設定) を参照してください。

**RDS for Oracle DB インスタンスからウェブサイトへのアクセスを設定するには**

1. RDS for Oracle DB インスタンスに、マスターユーザーとしてログインします。

1. セキュアなポートで、ユーザーと対象のウェブサイトの Host Access Control Entry (ACE) を作成します。

   次の例では、*my-user* ユーザーが、セキュアなポート 443 経由で *secret.encrypted-website.com* にアクセスできるように設定します。

   ```
   BEGIN
     DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
       host       => 'secret.encrypted-website.com', 
       lower_port => 443,
       upper_port => 443,
       ace        => xs$ace_type(privilege_list => xs$name_list('http'),
                                 principal_name => 'my-user',
                                 principal_type => xs_acl.ptype_db)); 
                              -- If the program unit results in PLS-00201, set
                              -- the principal_type parameter to 2 as follows:
                              -- principal_type => 2));
   END;
   /
   ```
**重要**  
前述のプログラムユニットでは、次のエラーが発生する可能性があります: `PLS-00201: identifier 'XS_ACL' must be declared`。このエラーが返された場合は、`principal_type` に値を割り当てる行を次の行に置き換えてから、プログラムユニットを再実行します。  

   ```
   principal_type => 2));
   ```
PL/SQL パッケージ `XS_ACL` の定数の詳細については、Oracle Database ドキュメントの「[https://docs.oracle.com/en/database/oracle/oracle-database/19/dbfsg/XS_ACL-package.html#GUID-A157FB28-FE23-4D30-AAEB-8224230517E7](https://docs.oracle.com/en/database/oracle/oracle-database/19/dbfsg/XS_ACL-package.html#GUID-A157FB28-FE23-4D30-AAEB-8224230517E7)」を参照してください。

   詳細については、Oracle Database のドキュメントの「[Configure Access Control Lists (ACLs) to External Network Services](https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/managing-fine-grained-access-in-pl-sql-packages-and-types.html#GUID-3D5B66BC-0277-4887-9CD1-97DB44EB5213)」(外部ネットワークサービスへのアクセス制御リスト (ACL) の構成) を参照してください。

1. (オプション) 標準のポートで、ユーザーと対象のウェブサイトの ACE を作成します。

   一部のウェブページが、セキュアポート (443) ではなく標準のウェブサーバーのポート (80) から提供される場合は、標準のポートを使用する必要がある場合があります。

   ```
   BEGIN
     DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
       host       => 'secret.encrypted-website.com', 
       lower_port => 80,
       upper_port => 80,
       ace        => xs$ace_type(privilege_list => xs$name_list('http'),
                                 principal_name => 'my-user',
                                 principal_type => xs_acl.ptype_db)); 
                              -- If the program unit results in PLS-00201, set
                              -- the principal_type parameter to 2 as follows:
                              -- principal_type => 2));
   END;
   /
   ```

1. アクセスコントロールエントリが存在することを確認します。

   ```
   SET LINESIZE 150
   COLUMN HOST FORMAT A40
   COLUMN ACL FORMAT A50
   
   SELECT HOST, LOWER_PORT, UPPER_PORT, ACL
     FROM DBA_NETWORK_ACLS
   ORDER BY HOST;
   ```

1. データベースユーザーに対して、`UTL_HTTP` パッケージを使用するアクセス許可を付与します。

   次の PL/SQL プログラムは、*my-user* ユーザーに対して、`UTL_HTTP` へのアクセス許可を付与します。

   ```
   BEGIN 
     rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('my-user')); 
     END;
   /
   ```

1. 関連するアクセスコントロールリストが存在することを確認します。

   ```
   SET LINESIZE 150
   COLUMN ACL FORMAT A50
   COLUMN PRINCIPAL FORMAT A20
   COLUMN PRIVILEGE FORMAT A10
   
   SELECT ACL, PRINCIPAL, PRIVILEGE, IS_GRANT,
          TO_CHAR(START_DATE, 'DD-MON-YYYY') AS START_DATE,
          TO_CHAR(END_DATE, 'DD-MON-YYYY') AS END_DATE
     FROM DBA_NETWORK_ACL_PRIVILEGES
   ORDER BY ACL, PRINCIPAL, PRIVILEGE;
   ```

1. クライアント認証で証明書を使用し、接続で Oracle ウォレットを使用するためのアクセス許可を、データベースユーザーに付与します。
**注記**  
認証にクライアント証明書を使用していない場合は、このステップを省略できます。

   ```
   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_DIR';
     DBMS_NETWORK_ACL_ADMIN.APPEND_WALLET_ACE(
       wallet_path => 'file:/' || l_wallet_path,
       ace         =>  xs$ace_type(privilege_list => xs$name_list('use_client_certificates'),
                                   principal_name => 'my-user',
                                   principal_type => xs_acl.ptype_db));
   END;
   /
   ```

## ステップ 6: DB インスタンスからウェブサイトへの接続をテストする
<a name="test_utl_http"></a>

このステップでは、`UTL_HTTP` やアップロードした Oracle ウォレット、クライアント証明書を使用してウェブサイトに接続できるように、データベースユーザーを設定します。

**RDS for Oracle DB インスタンスからウェブサイトへのアクセスを設定するには**

1. RDS for Oracle DB インスタンスに、`UTL_HTTP` へのアクセス許可を持つデータベースユーザーとしてログインします。

1. 対象のウェブサイトへ接続する際に、ホストアドレスを解決できることを確認します。

   次の例では、*secret.encrypted-website.com* からホストアドレスを取得します。

   ```
   SELECT UTL_INADDR.GET_HOST_ADDRESS(host => 'secret.encrypted-website.com')
     FROM DUAL;
   ```

1. 失敗した接続をテストします。

   `UTL_HTTP` は、証明書とともに Oracle ウォレットの場所を要求するため、次のクエリは失敗します。

   ```
   SELECT UTL_HTTP.REQUEST('secret.encrypted-website.com') FROM DUAL;
   ```

1. `UTL_HTTP.SET_WALLET` を使用し、`DUAL` から選択した場合の、ウェブサイトへのアクセスをテストします。

   ```
   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_DIR';
     UTL_HTTP.SET_WALLET('file:/' || l_wallet_path);
   END;
   /
   
   SELECT UTL_HTTP.REQUEST('secret.encrypted-website.com') FROM DUAL;
   ```

1. (オプション) クエリを変数に保存し、`EXECUTE IMMEDIATE` を使用した場合の、ウェブサイトへのアクセスをテストします。

   ```
   DECLARE
     l_wallet_path all_directories.directory_path%type;
     v_webpage_sql VARCHAR2(1000);
     v_results     VARCHAR2(32767);
   BEGIN
     SELECT DIRECTORY_PATH
       INTO l_wallet_path 
       FROM ALL_DIRECTORIES
      WHERE UPPER(DIRECTORY_NAME)='WALLET_DIR';
     v_webpage_sql := 'SELECT UTL_HTTP.REQUEST(''secret.encrypted-website.com'', '''', ''file:/' ||l_wallet_path||''') FROM DUAL';
     DBMS_OUTPUT.PUT_LINE(v_webpage_sql);
     EXECUTE IMMEDIATE v_webpage_sql INTO v_results;
     DBMS_OUTPUT.PUT_LINE(v_results);
   END;
   /
   ```

1. (オプション) ファイルシステム上で、Oracle ウォレットディレクトリの場所を検索します。

   ```
   SELECT * FROM TABLE(rdsadmin.rds_file_util.listdir(p_directory => 'WALLET_DIR'));
   ```

   前のコマンドからの出力を使用して、HTTP リクエストを作成します。例えば、ディレクトリが *rdsdbdata/userdirs/01* である場合、次のクエリを実行します。

   ```
   SELECT UTL_HTTP.REQUEST('https://secret.encrypted-website.com/', '', 'file://rdsdbdata/userdirs/01') 
   FROM   DUAL;
   ```