Amazon RDS Oracle 지갑의 CA 인증서 번들을 사용하여 SSL/TLS 엔드포인트에 연결하려면 어떻게 해야 합니까?

최종 업데이트 날짜: 2021년 4월 27일

Oracle을 실행하는 Amazon Relational Database Service(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 1Starfield Services 루트 인증 기관 - 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 설명서에서 Managing Oracle wallets with orapki utility를 참조하세요. 지갑을 생성할 디렉터리를 찾아봅니다. 그런 다음, 로컬 워크스테이션의 명령줄에서 다음과 유사한 명령을 실행합니다.

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

6.    로컬 워크스테이션의 명령줄에서 다음과 유사한 명령을 실행하여 두 개의 인증서를 지갑에 추가합니다.

>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.    이전 단계의 task-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은 기본적으로 한 시간 동안 유효합니다. 자세한 내용은 사전 서명에 대한 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_presigned_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 이 디렉터리는 RDS Oracle 인스턴스에서 S3 웹 서비스에 대한 인증서를 포함하는 지갑을 저장하는 데 사용됩니다.

HTTP를 사용하여 S3 웹 서비스를 사용하려는 경우 다음 예제 코드를 사용할 수 있습니다.

참고: "http"를 이전에 생성된 S3 미리 서명된 URL에서 "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 웹 서비스를 사용하려는 경우 다음 예제 코드를 사용할 수 있습니다.

참고: HTTPS를 사용하는 경우 RDS 인스턴스 디렉터리 S3_SSL_WALLET에 S3 웹 서비스 지갑을 저장하는 것이 전제 조건입니다.

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 인스턴스 없음).