如何使用 Amazon RDS Oracle 钱包中的 CA 证书包连接到 SSL/TLS 端点?

7 分钟阅读
0

我想从我的 Amazon Relational Database Service(Amazon RDS)安全地与外部 SSL/TLS 端点进行通信,以获得具有 Oracle 钱包的Oracle 数据库实例。

解决方案

**注意:**如果在运行 AWS 命令行界面(AWS CLI)命令时收到错误,请参阅 Troubleshoot AWS CLI errors。此外,确保您使用的是最新版本的 AWS CLI

下载目标 SSL/TLS 端点根证书和中间证书

  1. 在 Web 浏览器中,打开要访问的 URL(Web 服务的 SSL/TLS 端点)。

  2. 若要在浏览器的地址栏中查看证书详细信息,请选择挂锁符号。或者,在本地工作站的命令行上运行类似于以下内容的命令:

    **注意:**将 status.aws.amazon.com 替换为想要访问的 URL。

    $ openssl s_client -connect status.aws.amazon.com:443
    CONNECTED(00000003)
    depth=2 C = US, O = Amazon, CN = Amazon Root CA 1
    verify return:1
    depth=1 C = US, O = Amazon, CN = Amazon RSA 2048 M01
    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, CN = Amazon RSA 2048 M01
     1 s:C = US, O = Amazon, CN = Amazon RSA 2048 M01
       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
  3. 下载证书提供商中列出的相关根证书和中间证书。在此示例中,堆栈跟踪表明您需要证书 Amazon Root CA 1Amazon RSA 2048 M01。从 Amazon Trust Services 存储库下载证书。

  4. 如果证书不能以 pem 格式下载,请以 DER/CRT 格式下载证书。要将下载的证书转换为 pem 格式,请在本地工作站的命令行上运行类似于以下内容的命令:

    $ openssl x509 -inform der -in "Amazon Root CA 1.der" -outform pem -out "Amazon Root CA 1.pem"
    $ openssl x509 -inform der -in "Amazon RSA 2048 M01.der" -outform pem -out "Amazon RSA 2048 M01.pem"

创建 Oracle 钱包,然后加载 SSL/TLS 端点根证书与中间证书

  1. 使用 orapki 实用程序来创建 Oracle 钱包。当您安装 Oracle 客户端软件时,orapki 实用程序可用。Oracle JDeveloper Studio 版本还包括 orapki 实用程序。必须在源数据库环境中创建钱包。

  2. 创建钱包时,有几个参数可供选择。例如,使用 auto_login_only 来创建不需要密码即可打开的自动登录钱包(cwallet.sso)。

  3. 导航到要在其中创建钱包的目录。然后,在本地工作站的命令行上运行下面的命令:

    cd /app/client/wallet>
    orapki wallet create -wallet . -auto_login_only
  4. 向钱包添加两个证书:

    orapki wallet add -wallet . -trusted_cert -cert "Amazon Root CA 1.pem" -auto_login_only
    orapki wallet add -wallet . -trusted_cert -cert "Amazon RSA 2048 M01.pem" -auto_login_only
  5. 验证钱包内容,然后确认您已添加证书:

    >ls -ltrh cwallet.sso
    -rw------- 1 oracle oinstall 2.3K Aug 13 11:39 cwallet.sso
    
    >orapki wallet display -wallet .Oracle PKI Tool Release 19.0.0.0.0 - Production
    Version 19.3.0.0.0
    Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
    
    Requested Certificates:
    User Certificates:
    Trusted Certificates:
    Subject:        CN=Amazon RSA 2048 M01,O=Amazon,C=US
    Subject:        CN=Amazon Root CA 1,O=Amazon,C=US

将钱包上传到 S3 存储桶

创建新的 Amazon Simple Storage Service(Amazon S3)存储桶或使用现有存储桶,然后上传钱包。如果使用 AWS CLI,请在创建 Oracle 钱包的客户端计算机上运行以下面的命令。或者,从 Amazon S3 控制台上传钱包。

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

**注意:**将 wallet4321 替换为您的 S3 存储桶的名称。

配置数据库用户和权限

  1. 使用 SQL*Plus 作为主要用户来连接到 RDS for Oracle 数据库实例。

  2. 向您希望能够使用 UTL_HTTP 包的数据库用户授予必要的权限:

    SQL> define 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.

    **注意:**将 app_user 替换为您希望能够运行 UTL_HTTP 命令的 RDS 数据库用户的名称。

  3. 为钱包创建一个目录:

    **注意:**最好将每个钱包存储在自己的目录中。

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

将钱包从 S3 存储桶下载到 RDS 数据库实例

**注意:**可以在有或没有 Amazon S3 集成的情况下完成此步骤。

使用 Amazon S3 集成

  1. 使用 Amazon S3 集成将钱包从 S3 存储桶下载到数据库实例。

  2. 要从 S3 存储桶下载钱包文件,请在连接到数据库实例的 SQL*Plus 会话中运行下面的命令。

    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
    1691935899410-1902
  3. 要查看结果,请使用上一步中的 task-id 来显示任务的输出文件。

    SQL> SELECT text FROM table(rdsadmin.rds_file_util.read_text_file('BDUMP','dbtask-1691935899410-1902.log'));
    OUTPUT
    2023-08-13 14:11:39.497 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.
    2023-08-13 14:11:39.552 UTC [INFO ] The task successfully listed the Amazon S3 objects for AWS Region us-east-1, bucket name wallet4321, and prefix cwallet.sso.
    2023-08-13 14:11:39.568 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.
    2023-08-13 14:11:39.719 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.
    2023-08-13 14:11:39.720 UTC [INFO ] The task finished successfully.
  4. 验证钱包是否已下载到数据库实例:

    SQL> select * from table (rdsadmin.rds_file_util.listdir(p_directory => 'WALLET'));
    FILENAME            TYPE         FILESIZE MTIME               
    ------------------- ---------- ---------- --------------------
    01/                 directory        4096 13-AUG-2023 14:11:39
    cwallet.sso         file             2349 13-AUG-2023 14:11:39
  5. 设置 UTL_HTTP 事务的钱包路径:

    SQL>  DECLAREl_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.
  6. 验证 Web 服务主机 DNS 名称解析:

    SQL> SELECT UTL\_INADDR.GET\_HOST\_ADDRESS(host => 'status.aws.amazon.com') FROM DUAL

    使用 Oracle 钱包来浏览远程 Web 服务 URL:

    SQL> SELECT utl_http.request('https://status.aws.amazon.com/robots.txt') AS ROBOTS_TXT FROM DUAL;
    ROBOTS_TXT
    --------------------------------------------------------------------------------
    {"message":"Not Found"}

没有 S3 集成

  1. 要允许 Oracle 的 ACL 上的出站流量,请在连接到数据库实例的 SQL*Plus 会话中运行下面的命令:

    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. 在连接到数据库实例的 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. 要生成预签名 URL,请使用 AWS CLI 运行下面的命令。默认情况下,预签名 URL 的有效期为一小时。

    >aws s3 presign s3://wallet4321/cwallet.sso
    
    https://wallet4321.s3.amazonaws.com/cwallet.sso?AWSAccessKeyId=AKIAJWTPIJJA4FAQURFA&Signature=u8ysKQyp4O6ws3Qy5qZak8PfmLE%3D&Expires=1588199836
  4. 要从 S3 存储桶下载钱包,请在连接到数据库实例的 SQL*Plus 会话中运行 s3_download_presigned_url 过程。在运行 s3_download_presigned_url 过程之前,更新下面的输入参数:

    p_s3 url - 输入您生成的预签名 URL

    p_local_filename - 输入钱包文件的名称

    p_local_directory - 输入您在数据库实例上创建的用于存储钱包的目录的名称

    p_wallet_directory - 输入 S3_SSL_WALLET。数据库实例使用此目录来存储包含 Amazon S3 Web 服务证书的钱包。

    请参阅下面使用 HTTP 访问 S3 Web 服务的示例命令。在运行该命令之前,请将预签名 URL 中的 https 替换为 http

    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 访问 Amazon S3 Web 服务的示例命令。

    **注意:**要使用 HTTPS,必须将 Amazon S3 Web 服务钱包存储在数据库实例目录 S3_SSL_WALLET 中。

    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. 验证钱包是否已下载到 RDS for Oracle 数据库实例:

    SQL> select * from table (rdsadmin.rds_file_util.listdir(p_directory => 'WALLET'));
    FILENAME            TYPE         FILESIZE MTIME               
    ------------------- ---------- ---------- --------------------
    01/                 directory        4096 13-AUG-2023 15:15:39
    cwallet.sso         file             2349 13-AUG-2023 15:15:39
  6. 设置 url_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. 验证 Web 服务主机 DNS 名称解析:

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

    使用 Oracle 钱包来浏览远程 Web 服务 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:错误的幻数

如果使用 AWS Key Management Service(AWS KMS)对 S3 存储桶及其内容进行加密,则会收到此错误。移除存储桶对象上的加密。

ORA-12535: TNS:操作超时

由于实例位于私有子网中,您可能会收到此错误。或者,路由表没有通往互联网的路由。

没有评论