Converting a non-CDB database to a PDB is a rather straightforward process. However once TDE (Transparent Data Encryption) gets involved certain things become not so obvious so I've decided to write a small guide on how to accomplish that. In order for a non-CDB database to be converted to a PDB it's version needs to be at least 12.1.0.2.0.
Encryption Wallet Location
My encryption wallet location is set to the following (sqlnet.ora):
ENCRYPTION_WALLET_LOCATION=
(SOURCE =
(METHOD = FILE)
(METHOD_DATA =
(DIRECTORY = /u01/app/oracle/admin/$ORACLE_SID/wallet/tde)
)
)
Create a non-CDB database
Let's start by creating a non-CDB database. I will call this database
db1 and it will later be converted to a pluggable database called
pdb1:
dbca -silent \
-createDatabase \
-templateName New_Database.dbt \
-gdbName db1 \
-createAsContainerDatabase false \
-sysPassword oracle \
-systemPassword oracle \
-emConfiguration none \
-datafileDestination /u02/oradata \
-redoLogFileSize 128 \
-recoveryAreaDestination /u02/fra \
-storageType FS \
-characterSet al32utf8 \
-nationalCharacterSet al16utf16 \
-automaticMemoryManagement false \
-initParams filesystemio_options=setall \
-initParams session_cached_cursors=100 \
-totalMemory 1024
Creating and starting Oracle instance
1% complete
...
100% complete
Since I have PSU2 applied I need to run
datapatch once the database has been created:
[oracle@ora12cr1 ~]$ . oraenv
ORACLE_SID = [oracle] ? db1
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@ora12cr1 ~]$ $ORACLE_HOME/OPatch/datapatch -verbose
Create the wallet and encrypted table
We're now ready to setup the wallet and create a user with an encrypted table:
[oracle@ora12cr1 ~]$ mkdir -p /u01/app/oracle/admin/db1/wallet/tde
[oracle@ora12cr1 ~]$ sqlplus / as sysdba
SQL*Plus: Release 12.1.0.2.0 Production on Sat Mar 7 15:51:21 2015
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
SQL> alter system set encryption key identified by "db1";
System altered.
SQL> alter system set db_create_file_dest='/u02/oradata';
System altered.
SQL> create tablespace encrypted datafile size 64m encryption using 'AES256' default storage (encrypt);
Tablespace created.
SQL> create user encrypt_user identified by "encrypt_user" default tablespace encrypted;
User created.
SQL> alter user encrypt_user quota unlimited on encrypted;
User altered.
SQL> create table encrypt_user.z_encrypted as
select dbms_random.string('x', 100) s
from dual
connect by level <= 100; 2 3 4
Table created.
Note that I did not use the new
administer key management syntax on purpose and instead created the wallet the old style way as I expect most of the existing environments to be the same. We will explore the significance of this in a moment.
Create a CDB
Before our non-CDB database can be converted to a PDB and plugged into a CDB we need to create the container database first:
[oracle@ora12cr1 ~]$ dbca -silent \
> -createDatabase \
> -templateName New_Database.dbt \
> -gdbName cdb12cr1 \
> -createAsContainerDatabase true \
> -sysPassword oracle \
> -systemPassword oracle \
> -emConfiguration none \
> -datafileDestination /u02/oradata \
> -redoLogFileSize 128 \
> -recoveryAreaDestination /u02/fra \
> -storageType FS \
> -characterSet al32utf8 \
> -nationalCharacterSet al16utf16 \
> -automaticMemoryManagement false \
> -initParams filesystemio_options=setall \
> -initParams session_cached_cursors=100 \
> -totalMemory 1024
Creating and starting Oracle instance
1% complete
...
100% complete
As before I need to run the
datapatch utility:
[oracle@ora12cr1 ~]$ . oraenv
ORACLE_SID = [oracle] ? cdb12cr1
The Oracle base remains unchanged with value /u01/app/oracle
[oracle@ora12cr1 ~]$ $ORACLE_HOME/OPatch/datapatch -verbose
Setup CDB with a wallet
Our newly created CDB needs to be setup with a wallet before we proceed with plugging a PDB which utilizes TDE. Let's do it now:
[oracle@ora12cr1 ~]$ mkdir -p /u01/app/oracle/admin/cdb12cr1/wallet/tde
[oracle@ora12cr1 ~]$ sqlplus / as sysdba
SQL*Plus: Release 12.1.0.2.0 Production on Sat Mar 7 17:23:58 2015
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
SQL> administer key management
create keystore '/u01/app/oracle/admin/cdb12cr1/wallet/tde'
identified by "cdb12cr1"; 2 3
keystore altered.
SQL> administer key management
set keystore open
identified by "cdb12cr1"; 2 3
keystore altered.
SQL> administer key management
set key identified by "cdb12cr1"
with backup; 2 3
keystore altered.
Here I have setup the wallet and the master encryption key using the new syntax.
Wallets
Before we move forward let's explore the differences between
db1 (created using the old syntax) and
cdb12cr1 (created using the new syntax) wallets:
[oracle@ora12cr1 ~]$ orapki wallet display -wallet /u01/app/oracle/admin/db1/wallet/tde
Oracle PKI Tool : Version 12.1.0.2
Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
Enter wallet password:
Requested Certificates:
Subject: CN=oracle
User Certificates:
Oracle Secret Store entries:
ORACLE.SECURITY.DB.ENCRYPTION.AY/sdMkWZk/4v3YgBKzZtcIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY
ORACLE.SECURITY.ID.ENCRYPTION.
ORACLE.SECURITY.KB.ENCRYPTION.
Trusted Certificates:
[oracle@ora12cr1 ~]$ orapki wallet display -wallet /u01/app/oracle/admin/cdb12cr1/wallet/tde
Oracle PKI Tool : Version 12.1.0.2
Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
Enter wallet password:
Requested Certificates:
Subject: CN=oracle
User Certificates:
Oracle Secret Store entries:
ORACLE.SECURITY.DB.ENCRYPTION.Ad+A607CLU+Ivx4f4E7KUYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY
ORACLE.SECURITY.ID.ENCRYPTION.
ORACLE.SECURITY.KB.ENCRYPTION.
ORACLE.SECURITY.KM.ENCRYPTION.Ad+A607CLU+Ivx4f4E7KUYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Trusted Certificates:
Notice how
db1 has the encryption key listed under
ORACLE.SECURITY.DB.ENCRYPTION while
cdb12cr1 in addition has the encryption key listed under the new
ORACLE.SECURITY.KM.ENCRYPTION as well.
In practice what I found is unless your encryption key is listed under
ORACLE.SECURITY.KM.ENCRYPTION it will not be exported when doing
administer key management export keys. As a result when you import the export file the master key required to decrypt the data will not be there potentially leaving you in a peculiar situation especially if you have used an in-place conversion. Even if you specifically export the key using the
with identifier in syntax you will not be able to import the key because specific key exports are not permitted to be imported into the PDBs.
Add ORACLE.SECURITY.KM.ENCRYPTION to db1's wallet
This step is only required if you created the wallet without using the new
administer key management syntax. Re-keying the wallet will generate a new master key preserving the old master key necessary to decrypt the data while adding missing
ORACLE.SECURITY.KM.ENCRYPTION entries at the same time. Execute while connected to
db1:
SQL> administer key management
set key identified by "db1"
with backup; 2 3
keystore altered.
If we look at the wallet we can see that it now contains the necessary entires:
[oracle@ora12cr1 ~]$ orapki wallet display -wallet /u01/app/oracle/admin/db1/wallet/tde
Oracle PKI Tool : Version 12.1.0.2
Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
Enter wallet password:
Requested Certificates:
Subject: CN=oracle
User Certificates:
Oracle Secret Store entries:
ORACLE.SECURITY.DB.ENCRYPTION.AXZlzWtP/U/xv+vihPzeaGkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.AY/sdMkWZk/4v3YgBKzZtcIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY
ORACLE.SECURITY.ID.ENCRYPTION.
ORACLE.SECURITY.KB.ENCRYPTION.
ORACLE.SECURITY.KM.ENCRYPTION.AXZlzWtP/U/xv+vihPzeaGkAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.KM.ENCRYPTION.AY/sdMkWZk/4v3YgBKzZtcIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.KM.ENCRYPTION.MASTERKEY
Trusted Certificates:
Prepare db1 to be converted into a PDB
Before
db1 can be plugged into a container database it needs to be converted to a PDB and it's encryption keys exported. Shutdown
db1 and open it in read only:
SQL> show parameter db_name
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_name string db1
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup mount restrict
ORACLE instance started.
Total System Global Area 1241513984 bytes
Fixed Size 2923872 bytes
Variable Size 452985504 bytes
Database Buffers 771751936 bytes
Redo Buffers 13852672 bytes
Database mounted.
SQL> alter database open read only;
Database altered.
We can now export the encryption keys:
SQL> administer key management
set keystore open
identified by "db1"; 2 3
keystore altered.
SQL> administer key management
export keys with secret "db1"
to '/u01/app/oracle/admin/cdb12cr1/wallet/tde/db1.exp'
identified by "db1"; 2 3 4
keystore altered.
Note that in order for the export operation to work the wallet needs to be explicitly opened with a password otherwise you will receive an error. In case of an auto login (local) wallet you will have to close the wallet and reopen it with a password.
The next step is to generate metadata necessary for PDB conversion and shutdown
db1 database:
SQL> exec dbms_pdb.describe(pdb_descr_file => '/u01/app/oracle/db1.xml');
PL/SQL procedure successfully completed.
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
Convert and plug db1 into a CDB
We can now login into
cdb12cr1 and perform in-place conversion of
db1 which does not requires any datafiles to be copied. Of course if something were to go wrong with the conversion process you might end up in a situation where you need to restore your original database from a backup so use this approach with care.
SQL> show parameter db_name
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
db_name string cdb12cr1
SQL> create pluggable database pdb1
using '/u01/app/oracle/db1.xml'
nocopy tempfile reuse; 2 3
Pluggable database created.
Before
pdb1 can be opened we need to run the script which will convert
pdb1's data dictionary:
SQL> alter session set container=pdb1;
Session altered.
SQL> @?/rdbms/admin/noncdb_to_pdb.sql
Once the script completes we can open
pdb1:
SQL> alter pluggable database pdb1 open;
Warning: PDB altered with errors.
The error while opening the PDB tells us that the encryption key is missing (can be seen in
pdb_plug_in_violations view). Let's go and import the key now:
[oracle@ora12cr1 ~]$ sqlplus / as sysdba
SQL*Plus: Release 12.1.0.2.0 Production on Sat Mar 7 18:22:23 2015
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
SQL> alter session set container=pdb1;
Session altered.
SQL> administer key management
set keystore open
identified by "cdb12cr1"; 2 3
keystore altered.
SQL> administer key management
import keys with secret "db1"
from '/u01/app/oracle/admin/cdb12cr1/wallet/tde/db1.exp'
identified by "cdb12cr1"
with backup; 2 3 4 5
keystore altered.
SQL> alter pluggable database pdb1 close;
Pluggable database altered.
SQL> alter pluggable database pdb1 open;
Pluggable database altered.
The encryption keys are now imported and we no longer get an error. Note that as with the export in order to import the keys the wallet must be explicitly opened with a password. We can verify that everything is in order by querying the encrypted table:
SQL> administer key management
set keystore open
identified by "cdb12cr1"; 2 3
keystore altered.
SQL> select count(*) from encrypt_user.z_encrypted;
COUNT(*)
----------
100