Introdução
Em alguns casos a a senha de uma wallet do TDE pode ser perdida se não for mantida adequadamente em um cofre de senhas. Um dos casos que eu mais vi nos últimos anos foi o de alguém criar um Database na OCI (DBCS ou ExaCS) com uma senha de SYS apenas para conseguir passar da tela que exige uma senha forte, e depois alterar a senha do SYS manualmente quando o banco de dados estava pronto.
Acontece que a menos que você tenha optado por informar uma senha separada para a wallet TDE no momento da criação do banco de dados, por padrão a senha da wallet é a mesma que você informa como senha do SYS na console OCI (DBCS e Exadata Cloud).
Dessa forma, caso o DBA opte por alterar a senha do SYS manualmente e não guarde a senha original em um cofre de senhas, o que pode acontecer é todas as operações normais do banco funcionarem por anos devido a existência da configuração de AUTOLOGIN da wallet. Depois de meses ou anos você se depare com a situação de precisar da senha da wallet para executar uma ação administrativa, e ai percebe que ninguém tem conhecimento da senha da wallet.
Como resolver
Não existe uma forma de se recuperar a senha perdida de uma wallet do TDE, e se você está numa situação que precisa acessar uma wallet da qual você não possui a senha, e ela não tem o arquivo de AUTOLOGIN (cwallet.sso), esse post não vai te ajudar.
No entanto se a sua wallet (arquivo ewallet.p12) está acompanhada do AUTOLOGIN (arquivo cwallet.sso), tem jeito de sair do outro lado, mas usando um procedimento que é recomendado executar somente em uma janela de manutenção.
Estratégia
Para conseguir o feito acima, considere um cenário de um banco de dados em RAC (2 nodes), o banco está aberto e operando normalmente com a wallet aberta em AUTOLOGIN.
O plano a ser seguido:
- Cria uma wallet nova em qualquer diretório do servidor (vai ser temporário)
- Faz um MERGE da Wallet em uso com a Wallet nova
- Faz um backup do conteúdo da wallet atual no filesystem
- Substitui os arquivos do diretório da Wallet atual pelos arquivos da Wallet nova
- OPCIONAL: Forçar o fechamento e abertura da Wallet ou Restart da instância
Nessa estratégia, o Oracle vai acessar o conteúdo da wallet atual sem pedir a senha devido ao autologin. Somente a Wallet nova será alterada, e somente ela precisará de senha (e nós temos a senha porque acabamos de criar)
IMPORTANTE: Esse procedimento assume que Wallet é dedicada para TDE, e somente as Master Encryption Keys serão migradas. Se a mesma wallet em uso atualmente contém outros itens necessários para o banco de dados, como certificados, connection strings e ou Oracle Secrets, considere que você você precisará criar ou importar esses objetos na nova wallet seguindo outros procedimentos que não são cobertos nesse post.
Procedimento
No exemplo usado nesse procedimento, considere os seguinte:
| Item | Usado no Exemplo |
|---|---|
| Caminho da wallet usada pelo banco | /acfs01/C02DB/wallet/tde |
| Caminho da wallet nova (temporário) | /home/oracle/new_wallet |
| Senha da wallet nova | “NewPassword123” |
1) Em um dos nodes, crie um diretório temporário para a nova wallet:
mkdir -p /home/oracle/new_wallet
2) Conectando na instância Oracle desse mesmo node, crie uma nova wallet dentro do diretório temporário:
ADMINISTER KEY MANAGEMENT CREATE KEYSTORE '/home/oracle/new_wallet' IDENTIFIED BY "NewPassword123";
3) Identifique o caminho da wallet em uso no momento:
SELECT WRL_PARAMETER FROM V$ENCRYPTION_WALLET WHERE CON_ID = 1;
4) Faça o MERGE das duas Wallets (a atual não é afetada):
ADMINISTER KEY MANAGEMENT MERGE KEYSTORE '/acfs01/C02DB/wallet/tde' INTO EXISTING KEYSTORE '/home/oracle/new_wallet' IDENTIFIED BY "NewPassword123" WITH BACKUP;
5) Cria o arquivo de AUTOLOGIN para a nova wallet:
ADMINISTER KEY MANAGEMENT CREATE AUTO_LOGIN KEYSTORE FROM KEYSTORE '/home/oracle/new_wallet' IDENTIFIED by "NewPassword123";
6) Faça uma verificação pra confirmar que o conteúdo das duas wallets são iguais:
orapki wallet display -wallet /acfs01/C02DB/wallet/tde orapki wallet display -wallet /home/oracle/new_wallet
7) Crie um backup da wallet atual:
zip -r /home/oracle/BACKUP_WALLET_ORIGINAL.zip /acfs01/C02DB/wallet/tde/*
IMPORTANTE: A partir desse ponto é recomendado uma janela de manutenção para fechar e reabrir a wallet, ou reiniciar o banco de dados, validando efetivamente que a wallet está funcionando mesmo após um restart.
The
ADMINISTER KEY MANAGEMENTmerge statement has no bearing on the configured TDE wallet that is in use. However, the merged TDE wallet can be used as the new configured database TDE wallet if you want. Remember that you must reopen the TDE wallet if you are using the newly created TDE wallet as the TDE wallet for the database at the location configured by theWALLET_ROOTparameter.
Fonte: 4.1.8.1 About Merging TDE Wallets
OBS: Nos meus testes, essa etapa de reabrir a wallet depois de colocá-lo no diretório do parâmetro WALLET_ROOT não se mostrou realmente necessário, mas é bom seguir a recomendação da documentação.
8) Substitua os arquivos do diretório usado pela instância, com os arquivos da nova wallet que acabou de criar:
cp /home/oracle/new_wallet/* /acfs01/C02DB/wallet/tde
9) Confirme que o status da nova WALLET está aberta normalmente em modo AUTOLOGIN:
set lines 400 col name format a8 col WRL_PARAMETER format a30 col STATUS format a20 col WALLET_TYPE format a12 SELECT nvl(P.NAME,'CDB$ROOT') as name, W.CON_ID, W.INST_ID, W.WRL_PARAMETER, W.STATUS, W.WALLET_TYPE FROM GV$ENCRYPTION_WALLET W LEFT JOIN V$PDBS P ON W.CON_ID = P.CON_ID ORDER BY 2,3;
10) RECOMENDADO: Fecha e abre a wallet, ou reinicia o banco de dados como validação.
ATENÇÃO: Esse passo causa indisponibilidade momentânea nas tabelas que usam TDE, não faça em produção sem uma janela de manutenção.
Se você optar por fechar e abrir a wallet, faça o seguinte:
! cd /acfs01/C02DB/wallet/tde/; mv cwallet.sso BKP.cwallet.sso administer key management set keystore close container=all; administer key management set keystore open identified by "NewPassword123" container=all; ! cd /acfs01/C02DB/wallet/tde/; cp BKP.cwallet.sso cwallet.sso administer key management set keystore close identified by "NewPassword123" container=all;
- A linha 1 e 2 fecham a Wallet AUTOLOGIN (wallet fechada)
- A linha 4 abre a wallet com a senha (wallet aberta)
- A linha 6 e 7 reabrem a wallet AUTOLOGIN (wallet aberta)
Se você tiver mais flexibilidade de janela, eu sugiro fazer um restart da instância apenas por garantia.
Demonstração
Caso de teste
O CDB abaixo está configurado com TDE e o PDB está configurado como United-Mode (compartilha a mesma wallet que o CDB root):
SQL> @wallet2
NAME CON_ID INST_ID WRL_PARAMETER STATUS WALLET_TYPE
-------- ---------- ---------- ------------------------------ -------------------- ------------
CDB$ROOT 1 1 /acfs01/C02DB/wallet/tde/ OPEN AUTOLOGIN
CDB$ROOT 1 2 /acfs01/C02DB/wallet/tde/ OPEN AUTOLOGIN
PDB$SEED 2 1 OPEN AUTOLOGIN
PDB$SEED 2 2 OPEN AUTOLOGIN
C02PDB1 3 1 OPEN AUTOLOGIN
C02PDB1 3 2 OPEN AUTOLOGIN
6 rows selected.
SQL>
SQL> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 C02PDB1 READ WRITE NO
SQL>
A senha da wallet atual é “Dibiei”, mas eu vou usar o script PL/SQL abaixo para alterar a senha com uma string aleatória gerada com a package DBMS_RANDOM, de modo que eu não saberei qual será a nova senha da wallet (simulando um cenário em que eu realmente desconheço a senha).
SQL> DECLARE
currentPassword varchar2(100) := 'Dibiei';
ramdonPassword varchar2(100);
vSQL varchar2(500);
BEGIN
SELECT DBMS_RANDOM.STRING('X', 15)
INTO ramdonPassword
FROM dual;
vSQL := 'ADMINISTER KEY MANAGEMENT ALTER KEYSTORE PASSWORD FORCE KEYSTORE
IDENTIFIED BY '|| currentPassword ||' SET '|| ramdonPassword ||' WITH BACKUP';
EXECUTE IMMEDIATE vSQL;
END;
/
PL/SQL procedure successfully completed.
E agora como teste de referência, vou tentar clonar o PDB que usa TDE, onde é necessário informar a senha da Wallet.
Esse comando vai falhar com a senha incorreta:
SQL> create pluggable database PDB_CLONE FROM C02PDB1 KEYSTORE IDENTIFIED BY "Dibiei";
create pluggable database PDB_CLONE FROM C02PDB1 KEYSTORE IDENTIFIED BY "Dibiei"
*
ERROR at line 1:
ORA-46627: keystore password mismatch
Testando a solução do post
Criando a nova walet e fazendo o MERGE:
SQL> ! mkdir -p /home/oracle/new_wallet
SQL>
SQL> ADMINISTER KEY MANAGEMENT
CREATE KEYSTORE '/home/oracle/new_wallet'
IDENTIFIED BY "NewPassword123";
keystore altered.
SQL> SELECT WRL_PARAMETER FROM V$ENCRYPTION_WALLET WHERE CON_ID = 1;
WRL_PARAMETER
------------------------------
/acfs01/C02DB/wallet/tde/
SQL> ADMINISTER KEY MANAGEMENT
MERGE KEYSTORE '/acfs01/C02DB/wallet/tde'
INTO EXISTING KEYSTORE '/home/oracle/new_wallet'
IDENTIFIED BY "NewPassword123"
WITH BACKUP;
keystore altered.
SQL>
SQL> ADMINISTER KEY MANAGEMENT
CREATE AUTO_LOGIN KEYSTORE FROM KEYSTORE '/home/oracle/new_wallet'
IDENTIFIED by "NewPassword123";
keystore altered.
SQL>
SQL> exit
Validando a wallet:
[oracle@c02db01 ~]$ orapki wallet display -wallet /acfs01/C02DB/wallet/tde
Oracle PKI Tool Release 19.0.0.0.0 - Production
Version 19.4.0.0.0
Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
Requested Certificates:
Subject: CN=oracle
User Certificates:
Oracle Secret Store entries:
ORACLE.SECURITY.DB.ENCRYPTION.AfPYAARXZ081vxbwVi9vGnsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.AfZEmW1S6E8pv1JFpOWz6JsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY.1EE8057EB0C87EDFE0632A01A8C04958
ORACLE.SECURITY.ID.ENCRYPTION.
ORACLE.SECURITY.KB.ENCRYPTION.
ORACLE.SECURITY.KM.ENCRYPTION.AfPYAARXZ081vxbwVi9vGnsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.KM.ENCRYPTION.AfZEmW1S6E8pv1JFpOWz6JsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Trusted Certificates:
[oracle@c02db01 ~]$
[oracle@c02db01 ~]$ orapki wallet display -wallet /home/oracle/new_wallet
Oracle PKI Tool Release 19.0.0.0.0 - Production
Version 19.4.0.0.0
Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
Requested Certificates:
Subject: CN=oracle
User Certificates:
Oracle Secret Store entries:
ORACLE.SECURITY.DB.ENCRYPTION.AfPYAARXZ081vxbwVi9vGnsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.AfZEmW1S6E8pv1JFpOWz6JsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY
ORACLE.SECURITY.DB.ENCRYPTION.MASTERKEY.1EE8057EB0C87EDFE0632A01A8C04958
ORACLE.SECURITY.ID.ENCRYPTION.
ORACLE.SECURITY.KB.ENCRYPTION.
ORACLE.SECURITY.KM.ENCRYPTION.AfPYAARXZ081vxbwVi9vGnsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ORACLE.SECURITY.KM.ENCRYPTION.AfZEmW1S6E8pv1JFpOWz6JsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Trusted Certificates:
Substituindo a wallet usada pelo banco de dados pela que acabou de ser criada:
[oracle@c02db01 ~]$ zip -r /home/oracle/BACKUP_WALLET_ORIGINAL.zip /acfs01/C02DB/wallet/tde/*
adding: acfs01/C02DB/wallet/tde/cwallet.sso (stored 0%)
adding: acfs01/C02DB/wallet/tde/cwallet.sso.lck (stored 0%)
adding: acfs01/C02DB/wallet/tde/ewallet_2024091717385516.p12 (stored 0%)
adding: acfs01/C02DB/wallet/tde/ewallet_2024091719163970.p12 (stored 0%)
adding: acfs01/C02DB/wallet/tde/ewallet.p12 (stored 0%)
adding: acfs01/C02DB/wallet/tde/ewallet.p12.lck (stored 0%)
[oracle@c02db01 ~]$
[oracle@c02db01 ~]$ cp /home/oracle/new_wallet/* /acfs01/C02DB/wallet/tde
Reiniciando o banco (OPCIONAL):
[oracle@c02db01 ~]$ srvctl stop instance -d C02DB -i C02DB1
[oracle@c02db01 ~]$ srvctl start instance -d C02DB -i C02DB1
[oracle@c02db01 ~]$
[oracle@c02db01 ~]$ srvctl stop instance -d C02DB -i C02DB2
[oracle@c02db01 ~]$ srvctl start instance -d C02DB -i C02DB2
Validando que a wallet foi aberta com sucesso, assim como os PDBS:
SQL> @wallet2
NAME CON_ID INST_ID WRL_PARAMETER STATUS WALLET_TYPE
-------- ---------- ---------- ------------------------------ -------------------- ------------
CDB$ROOT 1 1 /acfs01/C02DB/wallet/tde/ OPEN AUTOLOGIN
CDB$ROOT 1 2 /acfs01/C02DB/wallet/tde/ OPEN AUTOLOGIN
PDB$SEED 2 1 OPEN AUTOLOGIN
PDB$SEED 2 2 OPEN AUTOLOGIN
C02PDB1 3 1 OPEN AUTOLOGIN
C02PDB1 3 2 OPEN AUTOLOGIN
6 rows selected.
SQL> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 C02PDB1 READ WRITE NO
SQL>
Testando a criação do clone do PDB novamente, agora com a nova senha da Wallet:
SQL> create pluggable database PDB_CLONE FROM C02PDB1 KEYSTORE IDENTIFIED BY "NewPassword123";
Pluggable database created.
SQL> alter pluggable database PDB_CLONE open;
Pluggable database altered.
SQL> show pdbs
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 C02PDB1 READ WRITE NO
5 PDB_CLONE READ WRITE NO
SQL> @wallet2
NAME CON_ID INST_ID WRL_PARAMETER STATUS WALLET_TYPE
--------------- ---------- ---------- ------------------------------ -------------------- ------------
CDB$ROOT 1 1 /acfs01/C02DB/wallet/tde/ OPEN AUTOLOGIN
CDB$ROOT 1 2 /acfs01/C02DB/wallet/tde/ OPEN AUTOLOGIN
PDB$SEED 2 1 OPEN AUTOLOGIN
PDB$SEED 2 2 OPEN AUTOLOGIN
C02PDB1 3 1 OPEN AUTOLOGIN
C02PDB1 3 2 OPEN AUTOLOGIN
PDB_CLONE 5 1 OPEN AUTOLOGIN
PDB_CLONE 5 2 OPEN AUTOLOGIN
8 rows selected.
Conclusão
Ao final desse procedimento você deve ter o banco de dados aberto como ele estava antes, usando uma nova wallet que você conhece a senha, contendo as Master Encryption Keys que foram migradas da wallet original. Agora basta guardar a senha de modo seguro, assim como é feito com a senha do SYS.
Como dica final, em um ambiente com RAC, considere que não há uma opção do comando “ADMINISTER KEY” que fecha a wallet em apenas uma das instâncias. Por esse motivo, se você pode reiniciar as instâncias do RAC em modo Rolling, isso resultará em menos impacto para as aplicações que usam as tabelas com TDE.