Introduction

This post is to describe the process of cloning an Oracle Database which is configured to store the TDE (encryption keys) in the Oracle Key Vault (OKV)

If the source database is configured with Oracle key Vault, than we can clone the database withouth having to transport the key files on the destination server.

In this exemple the clone will be made on the same host.

To install the RESTFul API and add a database as endpoint to OKV check my previous BLOG Add Oracle database server to Oracle Key vault (OKV) from scratch, only with RESTfull API.

The initial configuration is :

  • The source database name is CDB01
  • The target database name will be CDB02
  • The wallet_root database parameter on source database, CDB01, is set to /opt/oracle/admin/CDB01/wallet
  • The tde_configuration parameter on source database, CDB01, is set to KEYSTORE_CONFIGURATION=OKV|FILE. That means that the keystore is in OKV server and the auto login file is on local filesystem in /opt/oracle/admin/CDB01/wallet/tde path.
  • The source database is enrolled as an endpoint. A wallet was defined for the CDB01 endpoint, and the TDE keys are uploaded in this wallet.
  • On CDB01 the SYS password is tagged as sys_pwd
  • The endpoint password is tagged as endpoint_pwd
  • The RESTFul API is installed on the server in the path $HOME/okv
  • Finally, the name of the wallet defined in OKV which contains the TDE keys for CDB01 database is ORA_DB

The schema is something like this:

The CDB01 database store his keys in ORA_DB wallet. Normally it has the rights to read/write in this wallet. At enrol time, we are going to give the rights ro read the ORA_DB wallet to CDB02 endpoint (database).

I also use a simple sql script to check the wallet status at the database level:

[oracle@db ~]$ cat $HOME/tde.sql

set pages 200
set line 300
col WRL_PARAMETER format a50
col status forma a10
col pdb_name  format a20
select pdb_id, pdb_name, guid from dba_pdbs;
select * from v$encryption_wallet where con_id != 2;

Declare and enrol the endpoint for CDB02

The first step is the enrolment of the destination database, CDB02, and grant the rights to read the keys from OKV server.

Create the destination directory structure for CDB02.

[oracle@db ~]$ cat $HOME/okv/set_okv_rest_env.sh
export OKV_RESTCLI_CONFIG=$HOME/okv/conf
export JAVA_HOME=/usr/java/jdk-11.0.10
export OKV_HOME=$HOME/okv

# source the RESFul API environnement file 
[oracle@db ~]$ source $HOME/okv/set_okv_rest_env.sh

Create the database endpoint, for CDB02, using a JSON parameter file:

# create the JSON file for endpoint creation
[oracle@db ~]$ cat 01.create_endpoint_CDB02.json
{
  "service" : {
    "category" : "admin",
    "resource" : "endpoint",
    "action" : "create",
    "options" : {
      "endpoint" : "DB_CDB02",
      "description" : "DB server CDB02",
      "platform" : "LINUX64",
      "type" : "ORACLE_DB",
      "strictIpCheck" : "FALSE"
    }
  }
}

# create the endpoint on OKV
[oracle@db ~]$ $OKV_HOME/bin/okv admin endpoint create --from-json 01.create_endpoint_CDB02.json
{
  "result" : "Success"
}

Enrol the CDB02 endpoint.

# create the enroll endpoint JSON file  
[oracle@db ~]$ cat 02.provision_endpoint_CDB02.json
{
  "service" : {
    "category" : "admin",
    "resource" : "endpoint",
    "action" : "provision",
    "options" : {
      "endpoint" : "DB_CDB02",
      "location" : "/opt/oracle/admin/CDB02/wallet/okv",
      "autoLogin" : "FALSE"
    }
  }
}

# enroll the endopoint
[oracle@db ~]$ $OKV_HOME/bin/okv admin endpoint provision --from-json 02.provision_endpoint_CDB02.json
Enter Oracle Key Vault endpoint password: endpoint_pwd
{
  "result" : "Success"
}

Grant the access to the new CDB02 endpoint to read the wallet ORA_DB which keep the CDB01 TDE keys.

# create the grant access file to the wallet Keeping the source CDB01 Keys. 
[oracle@db ~]$ cat 04_grant_access_wallet_CDB02.json
{
  "service" : {
    "category" : "manage-access",
    "resource" : "wallet",
    "action" : "add-access",
    "options" : {
      "wallet" : "ORA_DB",
      "endpoint" : "DB_CDB02",
      "access" : "RM_MW"
    }
  }
}

# grant the access to the ORA_DB wallet for the endpoint.
[oracle@db ~]$ $OKV_HOME/bin/okv manage-access wallet add-access --from-json 04_grant_access_wallet_CDB02.json
{
  "result" : "Success"
}

Check that CDB02 endpoint can read the keys from CDB01 wallet.

# Test 
[oracle@db ~]$ /opt/oracle/admin/CDB02/wallet/okv/bin/okvutil list
Enter Oracle Key Vault endpoint password: endpoint_pwd
Enter Oracle Key Vault endpoint password:
Unique ID                               Type            Identifier
600D0743-01D9-4F2F-BF6F-C9E8AC74FF2A	Symmetric Key	TDE Master Encryption Key: TAG CDB:CDB01 MEK first
6A752388-F93D-4F14-BF35-39E674CAAFED	Symmetric Key	TDE Master Encryption Key: TAG REKEY CDB01
AB294686-1FC4-4FE8-BFAD-F56BAD0A124B	Symmetric Key	TDE Master Encryption Key: TAG REKEY CDB01
BB0CC77A-10AD-4F55-BF0A-9F5A4C7F98C1	Symmetric Key	TDE Master Encryption Key: TAG CDB:DBTDEOKV:PDB1 MEK first

At this level okvutil list for CDB02 endpoint, command return the keys available for CDB01 source database.

Clone the CDB01 to CDB02

Create an temporary init file with the TDE OKV parameters.

[oracle@db ~]$ cat /tmp/init.ora
db_name='CDB02'
wallet_root='/opt/oracle/admin/CDB02/wallet'
tde_configuration='KEYSTORE_CONFIGURATION=OKV|FILE';
enable_pluggable_database=true

Copy the Oracle password file /opt/oracle/product/19c/dbhome_1/dbs/orapwdCDB01 to /opt/oracle/product/19c/dbhome_1/dbs/orapdwCDB02.

Add the CDB02 as static identifier to the listener.

[oracle@db ~]$ cat $ORACLE_HOME/network/admin/listener.ora
LISTENER = (ADDRESS_LIST= (ADDRESS=(PROTOCOL=tcp)(HOST=db.sub05191447261.vcn01.oraclevcn.com)(PORT=1521)))

SID_LIST_LISTENER=
(SID_LIST=
.....
    (SID_DESC=
        (GLOBAL_DBNAME=CDB02)
        (SID_NAME=CDB02)
        (ORACLE_HOME=/opt/oracle/product/19c/dbhome_1)
    )
)

# restart the listener
[oracle@db ~]$ lsnrctl start listener
.....
Services Summary...
Service "CDB01" has 1 instance(s).
  Instance "CDB01", status UNKNOWN, has 1 handler(s) for this service...
Service "CDB02" has 1 instance(s).
  Instance "CDB02", status UNKNOWN, has 1 handler(s) for this service...
The command completed successfully

Set the CDB02 environnement and start the database using the temporary init file.

[oracle@db ~]$ . oraenv <<< CDB02

[oracle@db ~]$ sqlplus / as sysdba
SQL> startup nomount pfile='/tmp/init.ora'
SQL> exit;

[oracle@db ~]$ rman target sys/sys_pwd@CDB01 auxiliary sys/sys_pwd@CDB02

connected to target database: CDB01 (DBID=1690718290)
connected to auxiliary database: CDB02 (not mounted)

RMAN> run {
  allocate auxiliary channel aux1 device type disk;
  allocate auxiliary channel aux2 device type disk;

  duplicate target database to CDB02 from active database
  SPFILE 
  PARAMETER_VALUE_CONVERT 'CDB01' 'CDB02'
  NOFILENAMECHECK;
}

using target database control file instead of recovery catalog
allocated channel: aux1
channel aux1: SID=180 device type=DISK

allocated channel: aux2
channel aux2: SID=21 device type=DISK

Starting Duplicate Db at 26-MAR-24
current log archived

contents of Memory Script:
{
   restore clone from service  'CDB01' spfile to
 '/opt/oracle/product/19c/dbhome_1/dbs/spfileCDB02.ora';
   sql clone "alter system set spfile= ''/opt/oracle/product/19c/dbhome_1/dbs/spfileCDB02.ora''";
}
.....
contents of Memory Script:
{
   Alter clone database open resetlogs;
}
executing Memory Script

database opened

contents of Memory Script:
{
   sql clone "alter pluggable database all open";
}
executing Memory Script

sql statement: alter pluggable database all open
Finished Duplicate Db at 26-MAR-24

The clone is finished. Test the WALLET configuration

[oracle@db ~]$ . oraenv <<< CDB02

[oracle@db ~]$ sqlplus / as sysdba

SQL> @$HOME/tde

    PDB_ID PDB_NAME		GUID
---------- -------------------- --------------------------------
	 3 PDB01		0AE3AEC4EE5ACDB1E063A001A8ACB8BB
	 2 PDB$SEED		0AE38C7FF01EC651E063A001A8AC821E


WRL_TYPE  WRL_PARAMETER                         STATUS         WALLET_TYPE  WALLET_OR KEYSTORE FULLY_BAC CON_ID
--------- ------------------------------------- -------------- ------------ --------- -------- --------- ----------
FILE      /opt/oracle/admin/CDB02/wallet/tde/   NOT_AVAILABLE  UNKNOWN        SINGLE   NONE     UNDEFINED    1
OKV                                             CLOSED         UNKNOWN        SINGLE   NONE     UNDEFINED    1
FILE                                            NOT_AVAILABLE  UNKNOWN        SINGLE   UNITED   UNDEFINED    3
OKV                                             CLOSED         UNKNOWN        SINGLE   UNITED   UNDEFINED    3

-- the wallet is closed. Open it: 

SQL> administer key management set keystore open identified by "endpoint_pwd" container=all;

keystore altered.

SQL> @$HOME/tde

    PDB_ID PDB_NAME		GUID
---------- -------------------- --------------------------------
	 3 PDB01		0AE3AEC4EE5ACDB1E063A001A8ACB8BB
	 2 PDB$SEED		0AE38C7FF01EC651E063A001A8AC821E


WRL_TYPE  WRL_PARAMETER                        STATUS       WALLET_TYPE  WALLET_OR KEYSTORE FULLY_BAC  CON_ID
--------- ------------------------------------ ---------- -------------- --------- -------- --------- ----------
FILE      /opt/oracle/admin/CDB02/wallet/tde/  OPEN_NO_MA    AUTOLOGIN    SINGLE    NONE    UNDEFINED    1
                                               STER_KEY
OKV                                            OPEN          OKV          SINGLE    NONE    UNDEFINED    1
FILE                                           OPEN_NO_MA    AUTOLOGIN    SINGLE    UNITED  UNDEFINED    3
                                               STER_KEY
OKV                                            OPEN          OKV          SINGLE    UNITED  UNDEFINED    3

Finally create the auto login wallet, and restart the cloned database to validate the configuration.

[oracle@db ~]$ . oraenv <<< CDB02

[oracle@db ~]$ sqlplus / as sysdba
-- "OKV_PASSWORD" is used to open the wallet. 
-- "HSM_PASSWORD" is used to access the OKV server(s).
SQL> ADMINISTER KEY MANAGEMENT ADD SECRET 'endpoint_pwd' FOR CLIENT 'HSM_PASSWORD' TO AUTO_LOGIN KEYSTORE '/opt/oracle/admin/CDB02/wallet/tde';

-- check that the autologin wallet was created 
SQL> !ls /opt/oracle/admin/CDB02/wallet/tde
cwallet.sso 

SQL> startup force

SQL> show pdbs

    CON_ID CON_NAME			  OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
	 2 PDB$SEED			  READ ONLY  NO
	 3 PDB01			  MOUNTED

SQL> alter pluggable database PDB01 open;

Pluggable database altered.

SQL> @$HOME/tde

    PDB_ID PDB_NAME		GUID
---------- -------------------- --------------------------------
	 3 PDB01		0AE3AEC4EE5ACDB1E063A001A8ACB8BB
	 2 PDB$SEED		0AE38C7FF01EC651E063A001A8AC821E


WRL_TYPE  WRL_PARAMETER                        STATUS       WALLET_TYPE  WALLET_OR KEYSTORE FULLY_BAC  CON_ID
--------- ------------------------------------ ---------- -------------- --------- -------- --------- ----------
FILE      /opt/oracle/admin/CDB02/wallet/tde/  OPEN_NO_MA    AUTOLOGIN    SINGLE    NONE    UNDEFINED    1
                                               STER_KEY
OKV                                            OPEN          OKV          SINGLE    NONE    UNDEFINED    1
FILE                                           OPEN_NO_MA    AUTOLOGIN    SINGLE    UNITED  UNDEFINED    3
                                               STER_KEY
OKV                                            OPEN          OKV          SINGLE    UNITED  UNDEFINED    3

All PDB are correctly opened and the wallet are opened too.

Conclusion

The clone process can be fully automatised, and no wallet file must be transfered between the source and the destination server. With the keys in OKV the clone process is identically as withouth OKV. Keeping the keys in OKV is more secure as the principle “Zero touch keys” is respected, and DBA do not manipulate the keys.

Finally if we want to configure the database CDB02 to use another keys as the keys from CDB01, we can execute a REKEY operation.


Share on