使用证书和 Oracle Wallet 配置 UTL_HTTP 访问 - Amazon Relational Database Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

使用证书和 Oracle Wallet 配置 UTL_HTTP 访问

Amazon RDS 支持对 RDS for Oracle 数据库实例进行出站网络访问。要将数据库实例连接到网络,您可以使用以下 PL/SQL 软件包:

UTL_HTTP

此软件包从 SQL 和 PL/SQL 发出 HTTP 调用。您可以使用它通过 HTTP 访问 Internet 上的数据。有关详细信息,请参阅 Oracle 文档中的 UTL_HTTP

UTL_TCP

此软件包在 PL/SQL 中提供 TCP/IP 客户端访问功能。此软件包对于使用 Internet 协议和电子邮件的 PL/SQL 应用程序很有用。有关更多信息,请参阅 Oracle 文档中的 UTL_TCP

UTL_SMTP

此软件包提供 SMTP 命令的接口,以便客户端能够向 SMTP 服务器发送电子邮件。有关详细信息,请参阅 Oracle 文档中的 UTL_SMTP

您可以通过完成以下任务来配置 UTL_HTTP.REQUEST,以便与 SSL 握手期间需要客户端身份验证证书的网站搭配使用。您还可以通过修改 Oracle Wallet 生成命令和 DBMS_NETWORK_ACL_ADMIN.APPEND_WALLET_ACE 过程,为 UTL_HTTP 访问网站配置密码身份验证。有关更多信息,请参阅 Oracle Database 文档中的 DBMS_NETWORK_ACL_ADMIN

注意

您可为 UTL_SMTP 调整以下任务,以便通过 SSL/TLS(包括 Amazon Simple Email Service)发送电子邮件。

配置 UTL_HTTP 访问时的注意事项

在配置访问之前,请考虑以下事项:

  • 您可以将 SMTP 与 UTL_MAIL 选项结合使用。有关更多信息,请参阅Oracle UTL_MAIL

  • 远程主机的域名服务器 (DNS) 名称满足以下所有条件:

    • 可公开解析。

    • Amazon RDS 数据库实例的终端节点。

    • 可通过自定义 DNS 服务器解析。有关更多信息,请参阅“设置自定义 DNS 服务器”。

    • 同一 VPC 或对等 VPC 中的 Amazon EC2 实例的私有 DNS 名称。在这种情况下,请确认该名称可通过自定义 DNS 服务器解析。或者,要使用 Amazon 提供的 DNS,您可以启用 VPC 设置中的 enableDnsSupport 属性,并启用对 VPC 对等连接的 DNS 解析支持。有关更多信息,请参阅 VPC 中的 DNS 支持修改 VPC 对等连接

    • 若要安全地连接到远程 SSL/TLS 资源,建议创建和上传自定义 Oracle Wallet。使用与 Amazon RDS for Oracle 功能集成的 Amazon S3,您可以将 Wallet 从 Amazon S3 下载到 Oracle 数据库实例。有关 Oracle 的 Amazon S3 集成的信息,请参阅Amazon S3 集成

  • 如果为每个实例配置了 Oracle SSL 选项,您可以在 SSL/TLS 终端节点上的 Oracle 数据库实例之间建立数据库连接。无需作进一步配置。有关更多信息,请参阅Oracle 安全套接字层

步骤 1:获取网站的根证书

要在 RDS for Oracle 数据库实例与网站之间建立安全连接,请添加根 CA 证书。Amazon RDS 使用根证书将网站证书签署到 Oracle Wallet。

您可以通过各种方式获取根证书。例如,您可以执行以下操作:

  1. 使用 Web 服务器访问受证书保护的网站。

  2. 下载用于签名的根证书。

对于 Amazon 服务,根证书通常位于 Amazon Trust Services 存储库中。

步骤 2:创建 Oracle Wallet

创建包含 Web 服务器证书和客户端身份验证证书的 Oracle Wallet。RDS Oracle 实例使用 Web 服务器证书建立与网站的安全连接。网站需要客户端证书才能对 Oracle 数据库用户进行身份验证。

您可能希望在不使用客户端证书进行身份验证的情况下配置安全连接。在这种情况下,您可以跳过以下过程中的 Java 密钥库步骤。

创建 Oracle Wallet
  1. 将根证书和客户端证书放在一个目录中,然后更改到此目录。

  2. 将 .p12 客户端证书转换为 Java 密钥库。

    注意

    如果没有使用客户端证书进行身份验证,可以跳过此步骤。

    以下示例将名为 client_certificate.p12 的客户端证书转换为名为 client_keystore.jks 的 Java 密钥库。该密钥库随后会包含在 Oracle Wallet 中。密钥库密码为 P12PASSWORD

    orapki wallet pkcs12_to_jks -wallet ./client_certificate.p12 -jksKeyStoreLoc ./client_keystore.jks -jksKeyStorepwd P12PASSWORD
  3. 为 Oracle Wallet 创建与证书目录不同的目录。

    以下示例会创建 /tmp/wallet 目录。

    mkdir -p /tmp/wallet
  4. 在 Wallet 目录中创建 Oracle Wallet。

    以下示例将 Oracle Wallet 密码设置为 P12PASSWORD,这与之前步骤中 Java 密钥库使用的密码相同。虽然使用相同的密码很方便,但没有必要这样做。-auto_login 参数会打开自动登录功能,无需在每次访问时指定密码。

    注意

    作为安全最佳实践,请指定除此处所示提示以外的密码。

    orapki wallet create -wallet /tmp/wallet -pwd P12PASSWORD -auto_login
  5. 将 Java 密钥库添加到 Oracle Wallet 中。

    注意

    如果没有使用客户端证书进行身份验证,可以跳过此步骤。

    以下示例将密钥库 client_keystore.jks 添加到名为 /mp/wallet 的 Oracle Wallet 中。在此示例中,您为 Java 密钥库和 Oracle Wallet 指定了相同密码。

    orapki wallet jks_to_pkcs12 -wallet /tmp/wallet -pwd P12PASSWORD -keystore ./client_keystore.jks -jkspwd P12PASSWORD
  6. 将目标网站的根证书添加到 Oracle Wallet。

    以下示例将添加名为 Root_CA.cer 的证书。

    orapki wallet add -wallet /tmp/wallet -trusted_cert -cert ./Root_CA.cer -pwd P12PASSWORD
  7. 添加任何中间证书。

    以下示例将添加名为 Intermediate.cer 的证书。根据需要多次重复此步骤,以便加载所有中间证书。

    orapki wallet add -wallet /tmp/wallet -trusted_cert -cert ./Intermediate.cer -pwd P12PASSWORD
  8. 确认新创建的 Oracle Wallet 具有所需证书。

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

步骤 3:将 Oracle Wallet 下载到 RDS for Oracle 实例

在此步骤中,将 Oracle Wallet 上传到 Amazon S3,然后将 Wallet 从 Amazon S3 下载到 RDS for Oracle 实例。

将 Oracle Wallet 下载到 RDS for Oracle 数据库实例
  1. 完成 Amazon S3 与 Oracle 集成的先决条件,然后将 S3_INTEGRATION 选项添加到您的 Oracle 数据库实例。确保该选项的 IAM 角色具有您正在使用的 Amazon S3 存储桶的访问权限。

    有关更多信息,请参阅Amazon S3 集成

  2. 以主用户身份登录数据库实例,然后创建 Oracle 目录来保存 Oracle Wallet。

    以下示例将创建名为 WALLET_DIR 的 Oracle 目录。

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

    有关更多信息,请参阅在主数据存储空间中创建和删除目录

  3. 将 Oracle Wallet 上传到 Amazon S3 存储桶。

    您可以使用任何受支持的上传技术。

  4. 如果要重新上传 Oracle Wallet,请删除现有 Wallet。否则,请跳到下一步。

    以下示例将删除名为 cwallet.sso 的现有 Wallet。

    EXEC UTL_FILE.FREMOVE ('WALLET_DIR','cwallet.sso');
  5. 将 Oracle Wallet 从 Amazon S3 存储桶下载到 Oracle 数据库实例。

    以下示例会将名为 cwallet.sso 的 Wallet 从名为 my_s3_bucket 的 Amazon S3 存储桶下载到名为 WALLET_DIR 的数据库实例目录。

    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;
  6. (可选)下载受密码保护的 Oracle Wallet。

    仅在每次使用 Wallet 都需要密码时,才下载此 Wallet。以下示例将下载受密码保护的 Wallet 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;
  7. 检查数据库任务的状态。

    在以下示例中,将上述步骤返回的任务 ID 替换为 dbtask-1234567890123-4567.log

    SELECT TEXT FROM TABLE(rdsadmin.rds_file_util.read_text_file('BDUMP','dbtask-1234567890123-4567.log'));
  8. 检查用于存储 Oracle Wallet 的目录的内容。

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

    有关更多信息,请参阅列出数据库实例目录中的文件

步骤 4:授予用户 Oracle Wallet 权限

您可以创建新的数据库用户或配置现有用户。无论采用哪种方法,都必须配置用户使用证书访问 Oracle Wallet,以便实现安全连接和客户端身份验证。

授予用户 Oracle Wallet 权限
  1. 以主用户身份登录 RDS for Oracle 数据库实例。

  2. 如果不想配置现有数据库用户,可以选择创建新用户。否则,请跳到下一步。

    以下示例将创建名为 my-user 的数据库用户。

    CREATE USER my-user IDENTIFIED BY my-user-pwd; GRANT CONNECT TO my-user;
  3. 授予数据库用户对包含 Oracle Wallet 的目录的权限。

    以下示例将授予用户 my-user 对目录 WALLET_DIR 的读取访问权限。

    GRANT READ ON DIRECTORY WALLET_DIR TO my-user;
  4. 授予数据库用户对 UTL_HTTP 软件包的使用权限。

    以下 PL/SQL 计划授予用户 my-userUTL_HTTP 的访问权限。

    BEGIN rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('my-user')); END; /
  5. 授予数据库用户对 UTL_FILE 软件包的使用权限。

    以下 PL/SQL 计划授予用户 my-userUTL_FILE 的访问权限。

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

步骤 5:配置从数据库实例访问网站

在此步骤中,您将配置 Oracle 数据库用户,以便其可以使用 UTL_HTTP、上传的 Oracle Wallet 和客户端证书连接到目标网站。有关更多信息,请参阅 Oracle Database 文档中的配置对 Oracle Wallet 的访问控制

配置从 RDS for Oracle 数据库实例访问网站
  1. 以主用户身份登录 RDS for Oracle 数据库实例。

  2. 在安全端口上为用户和目标网站创建主机访问控制条目 (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 文档中的 Real Application Security Administrator's and Developer's Guide

    有关更多信息,请参阅 Oracle Database 文档中的为外部网络服务配置访问控制

  3. (可选)在标准端口上为用户和目标网站创建主机访问控制条目。

    如果是标准 Web 服务器端口 (80) 而不是安全端口 (443) 提供的网页,则可能需要使用标准端口。

    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; /
  4. 确认存在访问控制条目。

    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;
  5. 授予数据库用户对 UTL_HTTP 软件包的使用权限。

    以下 PL/SQL 计划授予用户 my-userUTL_HTTP 的访问权限。

    BEGIN rdsadmin.rdsadmin_util.grant_sys_object('UTL_HTTP', UPPER('my-user')); END; /
  6. 确认存在相关的访问控制列表。

    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;
  7. 授予数据库用户使用证书进行客户端身份验证和 Oracle Wallet 进行连接的权限。

    注意

    如果没有使用客户端证书进行身份验证,可以跳过此步骤。

    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:测试从数据库实例到网站的连接

在此步骤中,您将配置数据库用户,以便其可以使用 UTL_HTTP、上传的 Oracle Wallet 和客户端证书连接到网站。

配置从 RDS for Oracle 数据库实例访问网站
  1. 以具有 UTL_HTTP 权限的数据库用户身份登录 RDS for Oracle 数据库实例。

  2. 确认与目标网站的连接可以解析主机地址。

    以下示例将从 secret.encrypted-website.com 获取主机地址。

    SELECT UTL_INADDR.GET_HOST_ADDRESS(host => 'secret.encrypted-website.com') FROM DUAL;
  3. 测试失败连接。

    以下查询失败,因为 UTL_HTTP 需要带有证书的 Oracle Wallet 的位置。

    SELECT UTL_HTTP.REQUEST('secret.encrypted-website.com') FROM DUAL;
  4. 使用 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;
  5. (可选)将查询存储在变量中并使用 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; /
  6. (可选)查找 Oracle Wallet 目录的文件系统位置。

    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;