Introdução
Ao configurar o recurso Transparent Data Encryption (TDE) no banco de dados, por padrão a Master Encryption Key (MEK) é gerada automaticamente pelo Oracle, mas também temos a opção de criar uma “User-Defined Key“, usando uma chave gerada fora do banco de dados por qualquer ferramenta terceira que seja capaz de gerar uma chave compatível com o algoritmo que iremos usar no TDE (exemplo: AES256).
Essa opção permite atender requisitos de compliance mais exigentes, que restrigem ou determinam exatamente onde e como a chave principal deve ser gerada. Este post demonstra como criar e usar uma Master Encryption com opção User-Defined Key.
Para fins de demonstração, a chave utilizada será gerada com as bibliotecas do OPENSSL no Linux.
Requisitos
Para criar uma Master Encryption Key customizada, precisamos previamente gerar duas chaves para propósitos diferentes, e no formato compatível com o que é utilizado pelo Oracle, conforme abaixo:
KEY_ID
É o ID usado como identificador único da Encryption Key dentro da Wallet, assim como em views do dicionário de dados. Funciona como uma “Primary Key”, onde utilizamos esse valor para fazer referência a uma chave específica nos comandos “ADMINISTER KEY MANAGEMENT”.
Essa informação é importante porque uma wallet pode conter várias Master Encryption Keys diferentes devido as operações de REKEY, ou simplesmente porque cada PDB tem sua própria chave.
Esse valor deve ser gerado como uma chave de 16 bytes em formato hexadecimal.
Exemplo:
308e84705d62866a71fb8efd4b54779d
ENCRYPTION_KEY
É o conteúdo da Master Encryption Key propriamente dita, esse será o valor que o Oracle usará internamente durante as operações de encriptação, e não ficará visível ao consultar o conteúdo da wallet ou as views do dicionário de dados.
Para usar algoritmos de 256 bits, esse valor deve ser gerado com uma chave de 32 bytes em formato hexadecimal. Se for um algoritmo de 128 bits, a chave deve ser gerada com 16 bytes.
Exemplo com 32 bytes (usaremos AES256)
ee3a53eb1d42f7698c43b734668674f1c10db9c0af3175e092bea8d9aefc4609
Na documentação da Oracle, o valor de KEY_ID é referenciado como MKID, e o valor de ENCRYPTION_KEY é referenciado como MK.
Passo a passo
1) Gerando a chave fora do banco de dados
Essa etapa pode ser realizada em qualquer computador que tenha o openssl instalado (inclusive o seu notebook).
Garanta que você tem os pacotes necessários instalados na máquina (exemplo para Oracle Linux / RedHat):
dnf install openssl openssl-pkcs11 gnutls vim-common
1.1) Gere uma chave que será a Key ID usada como identificador único da MEK dentro da wallet:
openssl rand 16 | xxd -u -p
1.2) Gere a chave que será usada como a Master Encryption Key (MEK):
openssl rand -hex 32
2) Adicionando a Master Encryption Key na Wallet
2.1) No banco de dados, crie uma nova Master Encryption Key usando a sintaxe abaixo:
ADMINISTER KEY MANAGEMENT CREATE ENCRYPTION KEY '<KEY_ID>:<ENCRYPTION_KEY>' USING ALGORITHM '<ALGORITHM>' FORCE KEYSTORE IDENTIFIED BY "walletPassword" WITH BACKUP;
Exemplo usando as chaves geradas na etapa 1:
ADMINISTER KEY MANAGEMENT CREATE ENCRYPTION KEY '308e84705d62866a71fb8efd4b54779d:c280844095b55bf54ce35b5fd29aadfe332ad502d2d5b9bf56dd9d3a1a728b28' USING ALGORITHM 'AES256' FORCE KEYSTORE IDENTIFIED BY "WalletPassword" WITH BACKUP;
2.2) Consulte a chave recém criada na view V$ENCRYPTION_KEYS, o exemplo abaixo filtra o KEY_ID informado no comando anterior:
set lines 400
col key_id format a60
col key_use format a15
col creation_time format a20
col activation_time format a20
col tag format a20
SELECT KEY_ID,
KEY_USE,
TAG,
to_char(CREATION_TIME,'dd/mm/yyyy hh24:mi:ss') as creation_time,
to_char(ACTIVATION_TIME,'dd/mm/yyyy hh24:mi:ss') as activation_time
FROM V$ENCRYPTION_KEYS
WHERE substr( UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW( key_id )) ,3 ,32 ) = upper('308e84705d62866a71fb8efd4b54779d');
O Oracle armazena o KEY_ID encodado em formato BASE64, por isso precisamos usar a conversão para encontrar a chave com o valor original.
3) Ativando a Master Encryption Key
Com o KEY_ID retornado na query anterior, use a chave como Master Encryption Key do banco de dados:
ADMINISTER KEY MANAGEMENT USE KEY 'AdZUvaW9RU8yv7dpU5imRAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' FORCE KEYSTORE IDENTIFIED BY "WalletPassword" WITH BACKUP;
Note que neste comando aparece a palavra chave USE ao invés de CREATE.
Exemplo
[oracle@lab03 ~]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Wed Oct 2 19:01:50 2024
Version 19.24.0.0.0
Copyright (c) 1982, 2024, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.24.0.0.0
SQL> alter session set container = ORCLPDB2;
Session altered.
SQL>
SQL> @wallet
WALLET_ROOT
----------------------------------------------------------------------------------------------------
/u01/app/oracle/admin/ORCL/wallet
INST_ID WRL_TYPE CON_ID STATUS WALLET_TYPE WALLET_ORDER KEYSTORE FULLY_BACKED_UP
---------- ---------- ------ -------------------- --------------- --------------- -------- ---------------
1 FILE 4 OPEN_NO_MASTER_KEY AUTOLOGIN SINGLE UNITED UNDEFINED
SQL> SELECT CON_ID, STATUS FROM V$ENCRYPTION_WALLET;
CON_ID STATUS
------ --------------------
4 OPEN_NO_MASTER_KEY
SQL>
SQL> ADMINISTER KEY MANAGEMENT
CREATE ENCRYPTION KEY 'AD12D708627628F108C6DBD4A8C94B5A:bcaa9f8413bf5cb72dafcf96062812fb679b4807670e246d0d71a6e8734098c7'
USING TAG 'MY_CUSTOM_KEY4' -- opcional
USING ALGORITHM 'AES256'
FORCE KEYSTORE
IDENTIFIED BY "WalletPassword"
WITH BACKUP;
keystore altered.
SQL>
SQL> set lines 400
col key_id format a60
col key_use format a15
col creation_time format a20
col activation_time format a20
col tag format a20
SELECT KEY_ID,
KEY_USE,
TAG,
to_char(CREATION_TIME,'dd/mm/yyyy hh24:mi:ss') as creation_time,
to_char(ACTIVATION_TIME,'dd/mm/yyyy hh24:mi:ss') as activation_time
FROM V$ENCRYPTION_KEYS
WHERE substr(
UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW( key_id )) ,3 ,32
) = upper('AD12D708627628F108C6DBD4A8C94B5A');
KEY_ID KEY_USE TAG CREATION_TIME ACTIVATION_TIME
------------------------------------------------------------ --------------- -------------------- -------------------- --------------------
Aa0S1whidijxCMbb1KjJS1oAAAAAAAAAAAAAAAAAAAAAAAAAAAAA TDE IN PDB MY_CUSTOM_KEY4 02/10/2024 22:03:13
SQL>
SQL>
SQL> ADMINISTER KEY MANAGEMENT
USE KEY 'Aa0S1whidijxCMbb1KjJS1oAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
FORCE KEYSTORE
IDENTIFIED BY "WalletPassword"
WITH BACKUP;
keystore altered.
SQL>
SQL> SELECT CON_ID, STATUS FROM V$ENCRYPTION_WALLET;
CON_ID STATUS
------ --------------------
4 OPEN
DICA: Você também pode usar a opção IDENTIFIED BY EXTERNAL KEYSTORE em todos os comandos.
Separação de papéis
Diferente do valor de ENCRYPTION_KEY, o valor da KEY_ID não é necessariamente uma informação sensível. Por exemplo, em um cenário de separação de papéis onde um time de security gera as chaves e cria as Master Encryption Key dentro da wallet, mas o time de produção fica responsável por ativar essa MEK no banco de dados (Configuração nova ou REKEY), um DBA “A” pode criar a chave e compartilhar o valor do KEY_ID para o DBA “B” seguir com a ativação da mesma.
Conclusão
Conforme exemplo demonstrado neste post, podemos configurar o Oracle TDE com chaves geradas a partir de ferramentas terceiras, sendo útil para ter melhor rastreabilidade e controle das chaves que são usadas no ambiente, além de também ser possível atender requisitos de auditoria mais específicos.
Adicionalmente, a abordagem de configurar a chave em duas etapas (CREATE + USE), permite uma administração com separação de papéis, permitindo que um time realize a criação da chave, enquanto outro realize o processo de ativação.
Referência:
Advanced Security Guide: 4.2.1 Creating User-Defined TDE Master Encryption Keys