Introduction

The TDE database encryption is one of the main Oracle database feature usage. Once the TDE configured, the wallet must be backed up. If the wallet is lost nobody can help to recover the database. Also for security reasons is not a good idea to store the wallet with the database RMAN backups.

OKV was created to address these main points: store in a safe place the database encryption keys and avoid to keep the keys on the disk.

In this post I will show how to configure, from scratch, the TDE on the database, how to upload the wallet keys in the OKV and how to configure the database to use these keys.

I choose to make the full configuration using the OKV API, so it can be scripted and implemented on a new server.

The passwords are not hidden in order to easy find which password is used in which case.

So let’s start…

The steps

  • Configure the TDE at the datababse level.
  • Configure the OKV RESTfull API.
  • Add the endpoint server to the OKV.
  • Upload database keys to OKV.
  • Migrate from local keys usage to OKV.

Main configuration

Oracle Key Vault ip 172.168.0.41
Oracle Key Vault version21.7
Database Server ip 172.168.1.128
Database nameCDB01
Database version 21c

Configure TDE at database level

Create the directories

First let’s create some directories to keep the database wallet.

[oracle@okvcli oracle]$ export WALLET_DIR=/u01/app/oracle/wallet

[oracle@okvcli oracle]$ mkdir -p ${WALLET_DIR}/tde

[oracle@okvcli oracle]$ mkdir -p ${WALLET_DIR}/tde_seps

[oracle@okvcli oracle]$ mkdir -vp ${WALLET_DIR}/okv

[oracle@okvcli oracle]$ echo "export WALLET_DIR=/u01/app/oracle/wallet" >> $HOME/.bashrc

Set the TDE parameters

[oracle@okvcli oracle]$ . oraenv
ORACLE_SID = [CDB01] ?

[oracle@okvcli oracle]$ sqlplus / as sysdba

SQL> alter system set wallet_root = '/u01/app/oracle/wallet' scope=spfile;

SQL> alter system set tablespace_encryption_default_algorithm = 'AES256';

SQL> alter system set encrypt_new_tablespaces='ALWAYS';

SQL> shutdown immediate; 

SQL> startup; 

SQL> alter system set tde_configuration = "KEYSTORE_CONFIGURATION=FILE"

Wallet creation

SQL> select a.con_id, b.name, a.wrl_type, 
        a.wrl_parameter, a.status, 
        a.wallet_type 
from v$encryption_wallet a, 
         v$containers b 
where a.con_id=b.con_id 
order by a.con_id;

    CON_ID NAME       WRL_TYPE     WRL_PARAMETER                        STATUS                   WALLET_TYPE
---------- ---------- ------------ ------------------------------------ ------------------------------ ------------
     1     CDB$ROOT   FILE          /u01/app/oracle/wallet/tde/          NOT_AVAILABLE               UNKNOWN
     2     PDB$SEED   FILE                                               NOT_AVAILABLE               UNKNOWN
     3     PDB1       FILE                                               NOT_AVAILABLE               UNKNOWN

Create the keystore at CDB level

SQL> administer key management create keystore identified by "Hello123"; 

keystore altered.

SQL> administer key management add secret 'Hello123' for client 'TDE_WALLET' to local auto_login keystore '/u01/app/oracle/wallet/tde_seps';

keystore altered.

SQL> administer key management set keystore open identified by external store container=all;

keystore altered.

select a.con_id, b.name, a.wrl_type, 
       a.wrl_parameter, a.status, 
       a.wallet_type 
from v$encryption_wallet a, 
    v$containers b 
where a.con_id=b.con_id 
order by a.con_id;

    CON_ID NAME       WRL_TYPE     WRL_PARAMETER                        STATUS                WALLET_TYPE
---------- ---------- ------------ ------------------------------------ --------------------- ------------
     1     CDB$ROOT   FILE          /u01/app/oracle/wallet/tde/          OPEN_NO_MASTER_KEY    PASSWORD
     2     PDB$SEED   FILE                                               OPEN_NO_MASTER_KEY    PASSWORD
     3     PDB1       FILE                                               OPEN_NO_MASTER_KEY    PASSWORD

Create the master key password MEK at CDB and PDB level

SQL> administer key management set key using tag 'CDB1: Initial MEK' identified by external store with backup container=current;

Keystore altered.

SQL> select a.con_id, 
   b.name, a.wrl_type, a.wrl_parameter, a.status 
from v$encryption_wallet a, 
   v$containers b 
where a.con_id=b.con_id order by a.con_id;

CON_ID  NAME       WRL_TYPE      WRL_PARAMETER                    STATUS
---------- ---------- ------------ ------------------------------ ------------------------------
     1     CDB$ROOT   FILE          /u01/app/oracle/wallet/tde/   OPEN
     2     PDB$SEED   FILE                                        OPEN
     3     PDB1       FILE                                        OPEN_NO_MASTER_KEY

SQL> alter session set container=pdb1;

Session altered

SQL> administer key management set key using tag 'PDB1: Initial MEK' identified by external store with backup container=current;

Keystore altered.

SQL> alter session set container=CDB$ROOT;

Session altered.

SQL> select a.con_id, 
   b.name, a.wrl_type, a.wrl_parameter, a.status 
from v$encryption_wallet a, 
   v$containers b 
where a.con_id=b.con_id order by a.con_id;

CON_ID  NAME       WRL_TYPE      WRL_PARAMETER                    STATUS
---------- ---------- ------------ ------------------------------ ------------------------------
     1     CDB$ROOT   FILE          /u01/app/oracle/wallet/tde/   OPEN
     2     PDB$SEED   FILE                                        OPEN
     3     PDB1       FILE                                        OPEN

Create autologin wallet

SQL> show con_name

CON_NAME
------------------------------
CDB$ROOT

SQL> administer key management create local auto_login keystore from keystore '/u01/app/oracle/wallet/tde' identified by "Hello123";

keystore altered.

Configure OKV RESTfull service on oracle database server

[oracle@okvcli bin]$ export JAVA_HOME=/u01/app/oracle/product/21.0.0/dbhome_1/jdk

[oracle@okvcli bin]$ echo "export JAVA_HOME=/u01/app/oracle/product/21.0.0/dbhome_1/jdk" >> $HOME/.bashrc

[oracle@okvcli oracle]$ mkdir /u01/app/oracle/okvapi

[oracle@okvcli oracle]$ cd okvapi/

[oracle@okvcli okvapi]$ curl -O -k https://172.168.0.41:5695/okvrestclipackage.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 3865k  100 3865k    0     0   107M      0 --:--:-- --:--:-- --:--:--  107M

[oracle@okvcli okvapi]$ unzip okvrestclipackage.zip
Archive:  okvrestclipackage.zip
   creating: lib/
   creating: bin/
  inflating: bin/okv
  inflating: bin/okv.bat
   creating: conf/
  inflating: conf/okvrestcli.ini
  inflating: conf/okvrestcli_logging.properties
  inflating: lib/okvrestcli.jar

[oracle@okvcli okvapi]$ rm okvrestclipackage.zip

oracle@okvcli ~]$ export OKV_HOME=/u01/app/oracle/okvapi

[oracle@okvcli ~]$ echo "export OKV_HOME=/u01/app/oracle/okvapi" >> $HOME/.bashrc

[oracle@okvcli ~]$ cat $OKV_HOME/conf/okvrestcli.ini
[Default]
log_property=$OKV_HOME/conf/okvrestcli_logging.properties
server=172.168.0.41
okv_client_config=$WALLET_DIR/okv/conf/okvclient.ora
user=admin
client_wallet=$OKV_HOME/wallet

Edit the $OKV_HOME/bin/okv file and uncomment the line export OKV_RESTCLI_CONFIG=$OKV_RESTCLI_DIR/conf/okvrestcli.ini

Create the wallet for OKV RESTfull API

As for the okvrestcli.ini file I used the admin user (see user=admin from okvrestcli.ini) to configure the wallet. The password is the one defined in OKV for the admin user.

[oracle@okvcli okvapi]$ mkdir $OKV_HOME/wallet

[oracle@okvcli okvapi]$ $OKV_HOME/bin/okv admin client-wallet add --client-wallet $OKV_HOME/wallet --wallet-user admin
Password: ****** 
{
  "result" : "Success"
}

Test the correct installation of OKV RESTfull API

[oracle@okvcli conf]$ $OKV_HOME/bin/okv
{
  "restCLIVersion" : "21.7.0.0.0"
}

[oracle@okvcli okvapi]$  $OKV_HOME/bin/okv server info get
{
  "result" : "Success",
  "value" : {
    "caCertificateExpirationDate" : "2026-10-19 09:52:32",
    "cpuCores" : "4",
    "deploymentType" : "Standalone",
    "diskInGB" : "3652",
    "fraInGB" : "20",
    "memoryInKB" : "30504316",
    "serverCertificateExpirationDate" : "2024-10-19 09:57:11",
    "serverTime" : "2023-11-02 10:40:47",
    "version" : "21.7.0.0.0"
  }
}

At this moment the OKV RESTfull API is communicate with the OKV server. So we can use the API to add the endpoint to OKV.

Add the endpoint to OKV.

First we can create a wallet in the OKV for the endpoint. This step is optional. The name of the wallet is DBCDB01_WLT

[oracle@okvcli okvapi]$ $OKV_HOME/bin/okv manage-access wallet create --wallet DBCDB01_WLT
{
  "result" : "Success"
}

Now create the endpoint in the OKV

[oracle@okvcli okvapi]$ $OKV_HOME/bin/okv admin endpoint create --endpoint okvcli_host --description "$HOSTNAME, $(hostname -i)" --type ORACLE_DB --platform LINUX64
{
  "result" : "Success"
}

In the OKV the added endpoint is REGISTERED as is not enrolled yet:

As we create a wallet for this endpoint let’s define it as default wallet for it:

[oracle@okvcli okvapi]$ $OKV_HOME/bin/okv manage-access wallet set-default --wallet DBCDB01_WLT  --endpoint okvcli_host
{
  "result" : "Success"
}

Enroll the endpoint:

[oracle@okvcli okvapi]$ echo $ORACLE_HOME
/u01/app/oracle/product/21.0.0/dbhome_1

[oracle@okvcli okvapi]$ echo $ORACLE_BASE
/u01/app/oracle

[oracle@okvcli okvapi]$ $OKV_HOME/bin/okv admin endpoint provision --endpoint okvcli_host --location /u01/app/oracle/wallet/okv --auto-login FALSE
Enter Oracle Key Vault endpoint password: OKV_cli_123
{
  "result" : "Success"
}

The --location parameter must be wallet_root parameter path from the database plus okv. In this path OKV will download the okvutil file needed by the database to communicate with OKV server:

[oracle@okvcli okvapi]$ ls /u01/app/oracle/wallet/okv
bin  conf  csdk  jlib  lib  log  ssl

The okvclient.ora file from /u01/app/oracle/wallet/okv/conf path can be added in the $OKV_HOME/conf/okvrestcli.ini file: okv_client_config=/u01/app/oracle/wallet/okv/conf/okvclient.ora to be able to use the RESTfull API for this database.

Notice that I put the password in the command to identified it in the next steps.

At the end execute the root.sh script, which creates the directory tree /opt/oracle/extapi/64/hsm/oracle/1.0.0, changes ownership and permissions, then copies the PKCS#11 library into this directory.

The library PKCS#11 library liborapkcs.so is used by Oracle Database to communicate with OKV.

[opc@tstokvcli ~]$ sudo su -
[root@tstokvcli ~]# /u01/app/oracle/wallet/okv/bin/root.sh

At OKV server level the endpoint is enrolled now.

Let’s test if the endpoint okvutil is working:

oracle@okvcli ~]$ cd /u01/app/oracle/wallet/okv/bin

[oracle@okvcli bin]$ ./okvutil list
Enter Oracle Key Vault endpoint password:  OKV_cli_123
Unique ID                               Type            Identifier
3E32A151-D656-4E43-ADE8-629B11B8B4C9	Template	Default template for OKVCLI_HOST

At this moment we have the database encrypted with TDE, and the database server is able to communicate with the OKV server, and is enrolled in the OKV client.

The next step is to upload the TDE keys in the OKV.

Upload TDE key to OKV.

The first password id the wallet password (Hello123) the second password is the endpoint password (OKV_cli_123)

[oracle@okvcli bin]$ ./okvutil upload -t WALLET -l /u01/app/oracle/wallet/tde  -g DBCDB01_WLT -v 4
okvutil version 21.7.0.0.0
Endpoint type: Oracle Database
Configuration file: /u01/app/oracle/wallet/okv/conf/okvclient.ora
Server: 172.168.0.41:5696
Standby Servers:
Uploading from /u01/app/oracle/wallet/tde
Enter source wallet password:  Hello123
No auto-login wallet found, password needed
Enter Oracle Key Vault endpoint password: OKV_cli_123
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY
Trying to connect to 172.168.0.41:5696 ...
Connected to 172.168.0.41:5696.
ORACLE.SECURITY.DB.ENCRYPTION.AZXyYcD7Y0+Rv5tK3Y2lrT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.KM.ENCRYPTION.AZXyYcD7Y0+Rv5tK3Y2lrT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.KT.ENCRYPTION.AZXyYcD7Y0+Rv5tK3Y2lrT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.KB.ENCRYPTION.
ORACLE.SECURITY.ID.ENCRYPTION.
ORACLE.SECURITY.KT.ENCRYPTION.AezKLH/ZbU8ev0KGkyVh9XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.KM.ENCRYPTION.AezKLH/ZbU8ev0KGkyVh9XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.AezKLH/ZbU8ev0KGkyVh9XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY.0928CAFC93BBEE6CE0638001A8AC296F

Uploaded 2 TDE keys
Uploaded 0 SEPS entries
Uploaded 0 other secrets
Uploaded 4 opaque objects

Uploading private key
Uploading certificate request
Uploading trust points

Uploaded 1 private keys
Uploaded 1 certificate requests
Uploaded 0 user certificates
Uploaded 0 trust points

Upload succeeded

[oracle@okvcli bin]$ ./okvutil list
Enter Oracle Key Vault endpoint password: OKV_cli_123
Unique ID                               Type            Identifier
F1C1537B-970E-4F09-BF41-6E5525D92E28	Opaque Object	TDE Wallet Metadata
A2FE6566-A68E-5217-89B0-19370EF78066	Symmetric Key	TDE Master Encryption Key: TAG CDB1: Initial MEK
F3C5C8F1-5DBA-4FF2-BF28-4EC3E8606772	Opaque Object	TDE Wallet Metadata
3E77A59D-DB88-4F26-BF7C-5449137B46FE	Opaque Object	TDE Wallet Metadata
C910D912-0031-5776-AE3F-43967710B8DB	Symmetric Key	TDE Master Encryption Key: TAG PDB1: Initial MEK
0ABA58D9-7295-4F12-BFBF-F13382476355	Opaque Object	TDE Wallet Metadata
492260F0-113C-4F07-BFCA-25360F0173BC	Private Key	Private Key
4F1FC5D9-2C87-4F56-BF4B-6B3A5D730C6E	Opaque Object	Certificate Request
3E32A151-D656-4E43-ADE8-629B11B8B4C9	Template	Default template for OKVCLI_HOST

At database level we are still in the FILE keystore mode (local on the server).

SQL> select wrl_type, status, con_id from v$encryption_wallet;

WRL_TYPE         STATUS CON_ID
---------------- ------ ------
FILE             OPEN       1
FILE             OPEN       2
FILE             OPEN       3

At OKV server level the wallet DBCDB01_WLT contains our keys and the OKVCLI_HOST endpoint has access to the wallet:

Migrate the FILE local wallet to OKV

SQL> show con_id

CON_ID
------------------------------
1

SQL> alter system set tde_configuration = "KEYSTORE_CONFIGURATION=OKV|FILE" ;

SQL> administer key management set encryption key identified BY "OKV_cli_123"  migrate using "Hello123"  WITH BACKUP;

keystore altered.

The parameter "KEYSTORE_CONFIGURATION=OKV|FILE" means that the database will get the encryption key from OKV and the auto_login file cwallet.sso from local disk (/u01/app/oracle/wallet/tde)

Remove the auto_login file from the tde, directory in order to create the new auto_login file:

[oracle@okvcli tde]$ cd /u01/app/oracle/wallet/tde

[oracle@okvcli tde]$ rm cwallet.sso

Create the auto_login file for OKV access:

SQL> administer key management add secret 'OKV_cli_123' for client 'OKV_PASSWORD' to local auto_login keystore '/u01/app/oracle/wallet/tde';

keystore altered.

SQL> select wrl_type, status, con_id from v$encryption_wallet;

WRL_TYPE    STATUS    CON_ID
----------- -------- --------
FILE        OPEN      1
OKV         OPEN      1
FILE        OPEN      2
OKV         OPEN      2
FILE        OPEN      3
OKV         OPEN      3

At this step the database use OKV for the encryption key and local file for auto_login. In the wallet directory /u01/app/oracle/wallet/tde only the cwallet.sso file should exist.

Final test

The final test consist in the creation of an encrypted tablespace with a table inside, then clean local wallet (ewallet.p12 file ) and finally restart the database.

If everything is correctly configured then no password should be asked, the CDB and PDB(s) must be opened, the encrypted tablespace and the table must be accessible.

Let’s clean the /u01/app/oracle/wallet/tde directory (is a good practice to start by making a backup in another directory, just in case):

[oracle@okvcli tde]$ cd /u01/app/oracle/wallet/tde

[oracle@okvcli tde]$ mkdir bck

[oracle@okvcli tde]$ mv ewallet_* bck

[oracle@okvcli tde]$ ls 
cwallet.sso

Create an encrypted (ENCR_TBS) tablespace and add a table (ENCR_TABLE):

SQL> alter session set container=pdb1;

Session altered.

SQL> create tablespace encr_tbs;

SQL> select tablespace_name, encrypted from dba_tablespaces where tablespace_name='ENCR_TBS';

TABLESPACE_NAME 	       ENC
------------------------------ ---
ENCR_TBS		       YES

SQL> create table encr_table(c number) tablespace encr_tbs;

Table created.

SQL> insert into encr_table values(1);

1 row created.

SQL> commit;

Commit complete.

SQL> select * from encr_table;

	 C
----------
	 1

SQL> alter session set container=CDB$ROOT;

Session altered 

Finally restart the database and try to select the table:

SQL> shutdown immediate; 

SQL> startup; 

SQL> show pdbs;

   CON_ID  CON_NAME    OPEN MODE   RESTRICTED
---------- ----------- ----------- ---------- 
     2     PDB$SEED    READ ONLY    NO
     3     PDB1        READ WRITE   NO

SQL> alter session set container=pdb1;

Session altered.

SQL> select * from encr_table;

	 C
----------
	 1

Conclusion

Using OKV to store TDE encryption keys is the preferred solution. The RESTfull API proposed by OKV is complete and easy to configure. It is a good practice to script all commands in order to add the endpoints, and configure the database, as a post script of vm creation for instance.


Share on