Comment puis-je me connecter à un point de terminaison SSL/TLS à l'aide de certificats d'une autorité de certification dans le portefeuille Oracle Amazon RDS ?

Lecture de 13 minute(s)
0

Je possède une instance de base de données Amazon Relational Database Service (Amazon RDS) qui exécute Oracle. Je souhaite communiquer de façon sécurisée avec des points de terminaison SSL/TLS externes à partir de cette instance à l'aide du portefeuille Oracle.

Brève description

Certains utilitaires comme UTL_HTTP permettent de se connecter à des points de terminaison de serveur Web distants à partir d'une instance de base de données Oracle Amazon RDS. L'utilisation d'un portefeuille Oracle permet de sécuriser ce processus. Ce conteneur sert à stocker les certificats racine et intermédiaires nécessaires pour accéder au point de terminaison SSL/TLS d'un service Web.

Solution

Se connecter à des points de terminaison SSL/TLS externes à partir de votre instance à l'aide du portefeuille Oracle

1.    Dans votre navigateur Web, ouvrez l'URL (point de terminaison SSL/TLS du service Web) à laquelle vous souhaitez accéder.

2.    Affichez les détails du certificat dans la barre d'adresse de votre navigateur en cliquant sur le symbole du cadenas. Vous pouvez aussi exécuter une commande similaire à la suivante via l'interface de ligne de commande de votre poste de travail local.

$ 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
---

Remarque : veillez à remplacer status.aws.amazon.com par l'URL de votre choix.

3.    Téléchargez les certificats racine et intermédiaires adéquats à partir du fournisseur dédié. La trace de la pile indique que vous avez besoin des certificats Amazon Root CA 1 et Starfield Services Root Certificate Authority - G2. Vous pouvez les télécharger à partir du référentiel Amazon Trust Services. Si ces derniers sont disponibles au format PEM, aucune autre action n'est requise.

4.    Si les certificats ne sont pas disponibles au format PEM, téléchargez-les au format DER/CRT. Ensuite, convertissez-les au format PEM en exécutant une commande similaire à cet exemple depuis votre poste de travail local :

$ 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.    Créez un portefeuille à l'aide de l'utilitaire orapki, qui est disponible en installant le logiciel client Oracle approprié. Le portefeuille doit être créé dans l'environnement de base de données source. L'édition Oracle JDeveloper Studio inclut également l'utilitaire orapki. Lors de la création du portefeuille, vous devez spécifier plusieurs paramètres. Par exemple, vous pouvez utiliser auto_login_only pour créer une connexion automatique : ce portefeuille pourra donc être ouvert, modifié ou supprimé sans utiliser de mot de passe. Les autorisations du système de fichiers assurent la sécurité de ce type de portefeuilles à connexion automatique. Pour plus d'informations sur les autres options disponibles, reportez-vous à la documentation d'Oracle sur la gestion des portefeuilles Oracle avec l'utilitaire orapki. Accédez au répertoire dans lequel vous souhaitez créer le portefeuille. Ensuite, exécutez une commande similaire à la suivante via l'interface de ligne de commande de votre poste de travail local.

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

6.    Ajoutez les deux certificats au portefeuille en exécutant des commandes similaires à cet exemple depuis votre poste de travail local :

>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.    Affichez le contenu du portefeuille en exécutant la commande suivante depuis votre poste de travail local. Vérifiez que les certificats apparaissent.

>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.    Connectez-vous à l'instance de base de données Oracle Amazon RDS en utilisant SQL*Plus en tant qu'utilisateur principal. Accordez les privilèges nécessaires à l'utilisateur de base de données qui utilisera le package UTL_HTTP en exécutant une commande comme dans cet exemple :

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.    Dans la session SQL*Plus connectée à l'instance de base de données RDS, créez un répertoire pour le portefeuille en exécutant une commande similaire à la suivante :
Remarque : il est recommandé de stocker chaque portefeuille dans son propre répertoire.

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

10.    Créez un nouveau compartiment Amazon Simple Storage Service (Amazon S3) ou utilisez un compartiment existant pour charger le portefeuille. Si vous avez installé et configuré l'interface de ligne de commande AWS (AWS CLI), exécutez la commande suivante depuis l'ordinateur client sur lequel vous avez créé le portefeuille Oracle. Vous pouvez également télécharger le portefeuille à partir de la console Amazon S3.

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

Remarque : en cas d'erreurs lors de l'exécution de commandes depuis l'AWS CLI, assurez-vous d'utiliser la version la plus récente.

11.    Téléchargez le portefeuille à partir du compartiment S3 sur l'instance de base de données RDS, avec ou sans intégration Amazon S3.

Téléchargement du portefeuille à partir d'un compartiment S3 vers une instance RDS à l'aide de l'intégration Amazon S3

Pour télécharger le portefeuille à partir d'un compartiment S3 à l'aide de l'intégration Amazon S3, consultez la rubrique Intégration Amazon S3.

1.    Exécutez cette commande pour télécharger le fichier de portefeuille à partir d'un compartiment S3 vers le répertoire d'instance 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.    Consultez les résultats en affichant le fichier de sortie de la tâche à l'aide de l'identifiant de tâche utilisé lors de l'étape précédente afin de confirmer le téléchargement.

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.    Vérifiez que le portefeuille est téléchargé sur l'instance de base de données :

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.    Dans la session SQL*Plus connectée à l'instance de base de données RDS, définissez le chemin d'accès du portefeuille pour les transactions utl_http en exécutant une commande similaire à l'exemple suivant :

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.    Vérifiez la résolution du nom DNS de l'hôte du service Web en exécutant une commande comme celle-ci :

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

6.    Parcourez l'URL du service Web distant à l'aide du portefeuille Oracle en exécutant une commande similaire à cet exemple :

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

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

Pour savoir comment utiliser utl_http avec une instance Oracle, consultez la rubrique Configuration de l'accès réseau sortant sur votre instance de base de données Oracle.

Téléchargement du portefeuille à partir d'un compartiment S3 vers une instance RDS sans intégration Amazon S3 dans le groupe d'options RDS

1.    Dans la session SQL*Plus connectée à l'instance de base de données RDS, autorisez le trafic sortant sur l'ACL d'Oracle (à l'aide de l'utilisateur que vous avez défini) en exécutant une commande similaire à la suivante :

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.    Dans la session SQL*Plus connectée à l'instance de base de données RDS, créez la procédure suivante :

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.    Générez une URL présignée S3 en exécutant une commande similaire à la suivante :
Remarque : pour ce faire, vous devez installer et configurer l'interface AWS CLI sur l'ordinateur client. Par défaut, l'URL présignée est valide pendant une heure. Pour plus d'informations, consultez la référence de l'AWS CLI pour la commande presign.

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

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

4.    Dans la session SQL*Plus connectée à l'instance de base de données RDS, exécutez la procédure s3_download_presigned_url pour télécharger le portefeuille du compartiment S3 sur l'instance de base de données RDS. Veillez à mettre à jour les paramètres d'entrée de la procédure comme suit :
Remarque : vous pouvez télécharger le portefeuille à partir du compartiment S3 sur l'instance de base de données RDS via http ou https.

  • p_s3_url avec l'URL présignée S3 qui a été générée
  • p_local_filename avec le nom du fichier de portefeuille
  • p_local_directory avec le nom du répertoire créé sur l'instance Oracle RDS pour stocker le portefeuille
  • p_wallet_directory avec S3_SSL_WALLET. Ce répertoire est utilisé par l'instance Oracle RDS pour stocker le portefeuille contenant les certificats du service Web S3.

Pour utiliser le service Web S3 à l'aide de HTTP, vous pouvez utiliser l'exemple de code suivant :

Remarque : remplacez « http » par « https » dans l'URL présignée S3 précédemment générée.

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;
/

Pour utiliser le service Web S3 à l'aide de HTTPS, vous pouvez utiliser l'exemple de code suivant :

Remarque : le stockage du portefeuille du service Web S3 dans le répertoire d'instance RDS S3_SSL_WALLET est une condition préalable requise pour utiliser le protocole 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.    Vérifiez que le portefeuille est téléchargé sur l'instance de base de données :

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.    Dans la session SQL*Plus connectée à l'instance de base de données RDS, définissez le chemin d'accès du portefeuille pour les transactions utl_http en exécutant une commande similaire à la suivante :

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.    Vérifiez la résolution du nom DNS de l'hôte du service Web en exécutant une commande comme celle-ci :

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

8.    Parcourez l'URL du service Web distant à l'aide du portefeuille Oracle en exécutant une commande similaire à cet exemple :

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

Erreurs courantes

ORA-28759 : impossible d'ouvrir le fichier

Vous pouvez recevoir cette erreur si le portefeuille auquel vous faites référence ne se trouve pas dans l'emplacement que vous avez spécifié. Vous pouvez confirmer l'emplacement du fichier de portefeuille en listant les répertoires :

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

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

ORA-28768 : mauvais nombre magique

Vous pouvez recevoir cette erreur si le compartiment S3 et son contenu sont chiffrés à l'aide d'AWS Key Management Service (AWS KMS). Pour la résoudre, supprimez le chiffrement sur les objets du compartiment.

ORA-12535 : TNS : l'opération a expiré

Vous pouvez recevoir cette erreur dans les cas suivants :

  • L'instance de base de données se trouve dans un sous-réseau privé.
  • La table de routage n'est pas routée vers Internet (aucune passerelle ou instance NAT).

Informations connexes

Oracle sur Amazon RDS

Provisionnement de portefeuilles Oracle et accès aux points de terminaison SSL/TLS sur Amazon RDS for Oracle

Résolution de l'énigme utl_file dans Amazon RDS for Oracle