SQL Firewall no Oracle 26ai: exportando uma allowlist de homologação e importando em produção


Neste artigo iremos verificar como realizar a validação de uma allowlist em um ambiente de homologação e posteriormente importa-la em produção, evitando a necessidade de repetir todo o processo de captura da aplicação em cada um dos ambientes.

Para esta atividade será utilizado o DBMS_SQL_FIREWALL.EXPORT_ALLOW_LIST e IMPORT_ALLOW_LIST, incluindo validação antes do bloqueio e os cuidados com políticas já existentes.

Sobre os exemplos: este é um procedimento de referência baseado na documentação do Oracle AI Database 26ai e executado em um ambiente de teste.

1. Cenário e pré-requisitos

Item

    Exemplo

Origem

    ORA26AIHMG_PDB1,     com treinamento e allowlist já revisados

Destino

    ORA26AI_PDB1,              aberto para leitura e escrita

Usuário protegido

    FW_DEMO_APP               nos dois ambientes

O exemplo pressupõe nomes de schemas, objetos e usuários coerentes entre os ambientes. 

2. O que a exportação transporta — e o que não transporta

A API exporta a allowlist de um usuário em JSON, por meio de um CLOB. O conteúdo inclui SQLs permitidos, contextos e configurações da política, além dos SQL logs referenciados pelas entradas permitidas. Isso não equivale a exportar o histórico de captura ou de violações. Para transportar o conjunto de metadados de todos os usuários, existe a integração com Data Pump; ela tem outro escopo e não é a escolha deste exemplo.

Atenção para a existência de allowlist no destino (produção):

  • Sem allowlist no destino: a importação cria uma política com as configurações presentes no JSON, inclusive seu estado de ativação.
  • Com allowlist no destino: SQLs e contextos são mesclados; as configurações existentes permanecem. A importação não remove automaticamente entradas antigas.

3. Revisar a baseline em homologação

Onde executar: conectado ao PDB de homologação (ORA26AIHMG_PDB1), com a conta administrativa de SQL Firewall. A captura e a geração inicial da allowlist devem ter sido concluídas previamente.

SELECT SYS_CONTEXT('USERENV', 'CON_NAME') AS container_atual
FROM dual;

SELECT username, status, top_level_only, enforce, block
FROM dba_sql_firewall_allow_lists
WHERE username = 'FW_DEMO_APP';

SELECT username, COUNT(*) AS quantidade_sqls
FROM dba_sql_firewall_allowed_sql
WHERE username = 'FW_DEMO_APP'
GROUP BY username; SELECT * FROM dba_sql_firewall_allowed_ip_addr WHERE username = 'FW_DEMO_APP';

SELECT * FROM dba_sql_firewall_allowed_os_user WHERE username = 'FW_DEMO_APP';

SELECT * FROM dba_sql_firewall_allowed_os_prog WHERE username = 'FW_DEMO_APP
';

A contagem serve como conferência inicial; duas políticas com o mesmo número de SQLs podem permitir ações diferentes. Revise as assinaturas e os objetos acessados, além da quantidade. Verifique se o treinamento incluiu fluxos de fechamento, integrações, relatórios e exceções legítimas da aplicação.

IP, usuário do sistema operacional e nome do programa podem diferir entre homologação e produção.

4. Preparar os contextos e desabilitar a política de origem para transporte

Impacto: desabilitar uma allowlist interrompe sua aplicação para aquele usuário. Faça esta etapa somente na política de homologação destinada à promoção, após combinar a janela com os responsáveis. Não desabilite o SQL Firewall globalmente.

-- Executar somente em FW_DEMO_APPe somente se STATUS = ENABLED.
-- Se a allowlist ja estiver DISABLED, apenas confira o estado. SQL> show con_name; CON_NAME ------------------------------ ORA26AIHMG_PDB1 SQL> SQL> BEGIN DBMS_SQL_FIREWALL.DISABLE_ALLOW_LIST( username => 'FW_DEMO_APP' ); END; / 2 3 4 5 6 PL/SQL procedure successfully completed. SQL> set lines 210 SQL> SELECT username, status, top_level_only, enforce, block FROM dba_sql_firewall_allow_lists WHERE username = 'FW_DEMO_APP'; USERNAME STATUS TOP_LEVEL_ONLY ENFORCE BLOCK ---------------- -------- -------------- --------------- -------------- FW_DEMO_APP DISABLED Y ENFORCE_ALL Y

Resultado esperado: a linha de FW_DEMO_APP apresenta STATUS = DISABLED. Registre os valores anteriores para restaurar a proteção da homologação depois de exportar.

Caso necessário , segue o exemplo de ajuste de IP na política desabilitada. Os endereços abaixo são ilustrativos: substitua pelos endpoints efetivamente observados pelo banco e aprovados para produção.

BEGIN
  DBMS_SQL_FIREWALL.ADD_ALLOWED_CONTEXT(
    username     => 'FW_DEMO_APP',
context_type => DBMS_SQL_FIREWALL.IP_ADDRESS, value => '192.0.2.20' );
DBMS_SQL_FIREWALL.DELETE_ALLOWED_CONTEXT( username => 'FW_DEMO_APP',
context_type => DBMS_SQL_FIREWALL.IP_ADDRESS, value => '192.0.2.10' ); END; /

5. Exportar o CLOB para um arquivo JSON

Para transportar o CLOB sem depender de formatação de tela ou de limites de DBMS_OUTPUT, usarei o Python com o driver python-oracledb. O programa pode rodar em uma estação administrativa com acesso aos serviços dos PDBs; não precisa rodar no servidor do banco como realizado neste exemplo. 

python -m pip install oracledb

[root@oracle26ai ~]# python -m venv ~/venvs/fw-demo [root@oracle26ai ~]# source ~/venvs/fw-demo/bin/activate (fw-demo) [root@oracle26ai ~]# (fw-demo) [root@oracle26ai ~]# python -m pip install --upgrade oracledb Collecting oracledb Downloading https://files.pythonhosted.org/packages/e7/c4/00b05440b001a224423076e7b051d42acc6b1af1f40841ad65d3b3acdede/oracledb-1.4.2.tar.gz (495kB) 100% |████████████████████████████████| 501kB 2.6MB/s Complete output from command python setup.py egg_info: running egg_info creating pip-egg-info/oracledb.egg-info writing pip-egg-info/oracledb.egg-info/PKG-INFO writing dependency_links to pip-egg-info/oracledb.egg-info/dependency_links.txt writing requirements to pip-egg-info/oracledb.egg-info/requires.txt writing top-level names to pip-egg-info/oracledb.egg-info/top_level.txt writing manifest file 'pip-egg-info/oracledb.egg-info/SOURCES.txt' /tmp/pip-build-rniwo58j/oracledb/src/oracledb/__init__.py:39: UserWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in python-oracledb and will be removed in a future release warnings.warn(message) Traceback (most recent call last): File "<string>", line 1, in <module> File "/tmp/pip-build-rniwo58j/oracledb/setup.py", line 95, in <module> extra_compile_args=extra_compile_args) File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/__init__.py", line 129, in setup return distutils.core.setup(**attrs) File "/usr/lib64/python3.6/distutils/core.py", line 148, in setup dist.run_commands() File "/usr/lib64/python3.6/distutils/dist.py", line 955, in run_commands self.run_command(cmd) File "/usr/lib64/python3.6/distutils/dist.py", line 974, in run_command cmd_obj.run() File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/command/egg_info.py", line 278, in run self.find_sources() File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/command/egg_info.py", line 293, in find_sources mm.run() File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/command/egg_info.py", line 524, in run self.add_defaults() File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/command/egg_info.py", line 560, in add_defaults sdist.add_defaults(self) File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/command/py36compat.py", line 36, in add_defaults self._add_defaults_ext() File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/command/py36compat.py", line 119, in _add_defaults_ext build_ext = self.get_finalized_command('build_ext') File "/usr/lib64/python3.6/distutils/cmd.py", line 298, in get_finalized_command cmd_obj = self.distribution.get_command_obj(command, create) File "/usr/lib64/python3.6/distutils/dist.py", line 846, in get_command_obj klass = self.get_command_class(command) File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/dist.py", line 635, in get_command_class self.cmdclass[command] = cmdclass = ep.load() File "/root/venvs/fw-demo/lib64/python3.6/site-packages/pkg_resources/__init__.py", line 2318, in load return self.resolve() File "/root/venvs/fw-demo/lib64/python3.6/site-packages/pkg_resources/__init__.py", line 2324, in resolve module = __import__(self.module_name, fromlist=['__name__'], level=0) File "/root/venvs/fw-demo/lib64/python3.6/site-packages/setuptools/command/build_ext.py", line 17, in <module> from Cython.Distutils.build_ext import build_ext as _build_ext File "/tmp/pip-build-rniwo58j/oracledb/.eggs/cython-3.3.0-py3.6.egg/Cython/__init__.py", line 3, in <module> from .Shadow import __version__ File "/tmp/pip-build-rniwo58j/oracledb/.eggs/cython-3.3.0-py3.6.egg/Cython/Shadow.py", line 2 from __future__ import annotations ^ SyntaxError: future feature annotations is not defined ---------------------------------------- Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-rniwo58j/oracledb/ You are using pip version 9.0.3, however version 26.2.2 is available. You should consider upgrading via the 'pip install --upgrade pip' command. (fw-demo) [root@oracle26ai ~]# pip install --upgrade pip Collecting pip Downloading https://files.pythonhosted.org/packages/a4/6d/6463d49a933f547439d6b5b98b46af8742cc03ae83543e4d7688c2420f8b/pip-21.3.1-py3-none-any.whl (1.7MB) 100% |████████████████████████████████| 1.7MB 850kB/s Installing collected packages: pip Found existing installation: pip 9.0.3 Uninstalling pip-9.0.3: Successfully uninstalled pip-9.0.3 Successfully installed pip-21.3.1 You are using pip version 21.3.1, however version 26.2.2 is available. You should consider upgrading via the 'pip install --upgrade pip' command. (fw-demo) [root@oracle26ai ~]# pip install --upgrade pip Requirement already satisfied: pip in ./venvs/fw-demo/lib/python3.6/site-packages (21.3.1) (fw-demo) [root@oracle26ai ~]# (fw-demo) [root@oracle26ai ~]# python -c "import oracledb; print(oracledb.__version__)" Traceback (most recent call last): File "<string>", line 1, in <module> ModuleNotFoundError: No module named 'oracledb' (fw-demo) [root@oracle26ai ~]# (fw-demo) [root@oracle26ai ~]# python -m pip install --upgrade oracledb Collecting oracledb Downloading oracledb-1.4.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.8 MB) |████████████████████████████████| 7.8 MB 33.4 MB/s Collecting cryptography>=3.2.1 Downloading cryptography-40.0.2-cp36-abi3-manylinux_2_28_x86_64.whl (3.7 MB) |████████████████████████████████| 3.7 MB 43.6 MB/s Collecting cffi>=1.12 Downloading cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl (402 kB) |████████████████████████████████| 402 kB 46.2 MB/s Collecting pycparser Downloading pycparser-2.21-py2.py3-none-any.whl (118 kB) |████████████████████████████████| 118 kB 83.3 MB/s Installing collected packages: pycparser, cffi, cryptography, oracledb Successfully installed cffi-1.15.1 cryptography-40.0.2 oracledb-1.4.2 pycparser-2.21 (fw-demo) [root@oracle26ai ~]# python -c "import oracledb; print(oracledb.__version__)" /root/venvs/fw-demo/lib64/python3.6/site-packages/oracledb/__init__.py:39: UserWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in python-oracledb and will be removed in a future release warnings.warn(message) /root/venvs/fw-demo/lib64/python3.6/site-packages/oracledb/connection.py:45: CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography. The next release of cryptography will remove support for Python 3.6. from . import base_impl, thick_impl, thin_impl 1.4.2 (fw-demo) [root@oracle26ai ~]#

Sobre a execução acima: foi criado e ativado um ambiente virtual Python chamado fw-demo, pois a configuração do pip exigia esse isolamento para permitir a instalação de bibliotecas. Isso mantém as dependências do teste separadas das utilizadas pelo sistema operacional.

Em seguida, foi verificada a disponibilidade do oracledb, driver necessário para conectar o Python ao Oracle Database e executar as operações do teste com SQL Firewall. A verificação mostrou que o driver ainda não estava instalado nesse ambiente, sendo necessário instalá-lo para prosseguir.

Concluída a criação e ativação do ambiente virtual python. Connect com o usuário oracle e salve o script abaixo exportar_allowlist.py. O script exige que a política esteja desabilitada e não sobrescreve um arquivo existente.

[oracle@oracle26ai ~]$
[oracle@oracle26ai ~]$ cat exportar_allowlist.py
from getpass import getpass
from hashlib import sha256
from pathlib import Path
import json
import oracledb
oracledb.init_oracle_client()
print("Modo Thick ativo:", not oracledb.is_thin_mode())

arquivo = Path("FW_DEMO_APP_release_001.json")
dsn = input("DSN do PDB de HOMOLOGACAO: ").strip()
usuario = input("Conta administrativa: ").strip()
senha = getpass("Senha: ")

with oracledb.connect(user=usuario, password=senha, dsn=dsn,mode=oracledb.AUTH_MODE_SYSDBA) as conn:
    with conn.cursor() as cur:
        cur.execute("""
            SELECT status FROM dba_sql_firewall_allow_lists
            WHERE username = :usuario
        """, usuario="FW_DEMO_APP")
        estado = cur.fetchone()
        if estado is None or estado[0] != "DISABLED":
            raise RuntimeError("Origem deve possuir allowlist DISABLED")

        payload = cur.var(oracledb.DB_TYPE_CLOB)
        payload.setvalue(0, conn.createlob(oracledb.DB_TYPE_CLOB))
        cur.execute("""
            BEGIN
              DBMS_SQL_FIREWALL.EXPORT_ALLOW_LIST(
                username => :usuario, allow_list => :payload);
            END;
        """, usuario="FW_DEMO_APP", payload=payload)
        texto = payload.getvalue().read()
        json.loads(texto)  # Valida a sintaxe, sem reescrever o JSON.
        dados = texto.encode("utf-8")
        with arquivo.open("xb") as saida:
            saida.write(dados)
        print("Arquivo:", arquivo)
        print("SHA-256:", sha256(dados).hexdigest())
[oracle@oracle26ai ~]$

Execute com python exportar_allowlist.py. Registre o hash, a versão da aplicação, o PDB de origem, a data da revisão e a aprovação da mudança em um manifesto separado. O JSON pode conter informações sensíveis sobre SQL e infraestrutura: mantenha-o em repositório privado e transporte-o por canal autorizado.

[oracle@oracle26ai ~]$
[oracle@oracle26ai ~]$ python exportar_allowlist.py
Modo Thick ativo: True
DSN do PDB de HOMOLOGACAO: oracle26ai:1521/ora26aihmg_pdb1.publicsubnet.vcn01.oraclevcn.com
Conta administrativa: sys
Senha:
Arquivo: FW_DEMO_APP_release_001.json
SHA-256: cf0199f3c51f0b8740f432daa5237001f5749917d0112a4a59cc688c9df09f81
[oracle@oracle26ai ~]$
[oracle@oracle26ai ~]$

Após exportar, restaure na homologação os contextos e o estado de aplicação que eram necessários ao ambiente. A política de transporte não deve deixar a homologação desprotegida por esquecimento.

6. Importar no PDB de produção, sem ativação automática

Para importar a allowlist no pdb de produção, utilize o script abaixo importar_allowlist.py. Este processo interrompe a operação se encontrar allowlist ou captura para FW_DEMO_APP (Destino possui politica/captura para FW_DEMO_APP; revisar antes de importar); esse caso exige o tratamento da seção sobre políticas existentes.

[oracle@oracle26ai ~]$
[oracle@oracle26ai ~]$ cat importar_allowlist.py
from getpass import getpass
from hashlib import sha256
from pathlib import Path
import json
import oracledb

# Ativa o modo Thick antes de abrir qualquer conexão.
oracledb.init_oracle_client()
print("Modo Thick ativo:", not oracledb.is_thin_mode())

usuario_alvo = "FW_DEMO_APP"
arquivo = Path("FW_DEMO_APP_release_001.json")

# Valida o arquivo antes de conectar ao destino.
dados = arquivo.read_bytes()
hash_calculado = sha256(dados).hexdigest()

esperado = input("SHA-256 do manifesto aprovado: ").strip().lower()

if hash_calculado != esperado:
    raise RuntimeError("Hash diferente do manifesto")

texto = dados.decode("utf-8")
json.loads(texto)  # Valida a sintaxe sem reescrever o JSON.

print("Arquivo validado:", arquivo)
print("SHA-256:", hash_calculado)

dsn = input("DSN do PDB de PRODUCAO: ").strip()
usuario = input("Conta administrativa (somente o nome): ").strip()
senha = getpass("Senha: ")

with oracledb.connect(
    user=usuario,
    password=senha,
    dsn=dsn,
    mode=oracledb.AUTH_MODE_SYSDBA
) as conn:
    with conn.cursor() as cur:
        # Exibe o container efetivo da conexão.
        cur.execute("""
            SELECT SYS_CONTEXT('USERENV', 'CON_NAME')
            FROM dual
        """)
        container = cur.fetchone()[0]
        print("Container de destino:", container)

        if container in ("CDB$ROOT", "PDB$SEED"):
            raise RuntimeError(
                "Conecte diretamente ao PDB de destino"
            )

        # Confirma que o usuário existe no destino.
        cur.execute("""
            SELECT COUNT(*)
            FROM dba_users
            WHERE username = :usuario
        """, usuario=usuario_alvo)

        if cur.fetchone()[0] == 0:
            raise RuntimeError(
                "Usuario {} nao existe no PDB de destino".format(
                    usuario_alvo
                )
            )

        # Impede importação sobre política ou captura existente.
        # Os nomes das views são fixos; o usuário utiliza bind.
        for view in (
            "dba_sql_firewall_allow_lists",
            "dba_sql_firewall_captures"
        ):
            cur.execute(
                "SELECT COUNT(*) FROM {} "
                "WHERE username = :usuario".format(view),
                usuario=usuario_alvo
            )

            if cur.fetchone()[0]:
                raise RuntimeError(
                    "Destino possui registro em {} para {}; "
                    "importacao interrompida".format(
                        view, usuario_alvo
                    )
                )

        # Cria e preenche o CLOB temporário.
        # Não chamar close(): não houve open() explícito.
        payload = conn.createlob(oracledb.DB_TYPE_CLOB)
        payload.write(texto)

        cur.execute("""
            BEGIN
              DBMS_SQL_FIREWALL.IMPORT_ALLOW_LIST(
                username   => :usuario,
                allow_list => :payload
              );
            END;
        """, usuario=usuario_alvo, payload=payload)

        conn.commit()

        # Confirma a presença e o estado da lista importada.
        cur.execute("""
            SELECT username, status, enforce, block
            FROM dba_sql_firewall_allow_lists
            WHERE username = :usuario
        """, usuario=usuario_alvo)

        resultado = cur.fetchone()

        if resultado is None:
            raise RuntimeError(
                "Allowlist nao encontrada apos a importacao"
            )

        cur.execute("""
            SELECT COUNT(*)
            FROM dba_sql_firewall_allowed_sql
            WHERE username = :usuario
        """, usuario=usuario_alvo)

        quantidade_sql = cur.fetchone()[0]

        print("Importacao concluida.")
        print("Container:", container)
        print("Usuario:", resultado[0])
        print("Status:", resultado[1])
        print("Enforce:", resultado[2])
        print("Block:", resultado[3])
        print("Quantidade de SQLs permitidos:", quantidade_sql)
[oracle@oracle26ai ~]$

Execute com python importar_allowlist.py. 

[oracle@oracle26ai ~]$ python importar_allowlist.py
Modo Thick ativo: True
SHA-256 do manifesto aprovado: cf0199f3c51f0b8740f432daa5237001f5749917d0112a4a59cc688c9df09f81
Arquivo validado: FW_DEMO_APP_release_001.json
SHA-256: cf0199f3c51f0b8740f432daa5237001f5749917d0112a4a59cc688c9df09f81
DSN do PDB de PRODUCAO: oracle26ai:1521/ora26ai_pdb1.publicsubnet.vcn01.oraclevcn.com
Conta administrativa (somente o nome): sys
Senha:
Container de destino: ORA26AI_PDB1
Importacao concluida.
Container: ORA26AI_PDB1
Usuario: FW_DEMO_APP
Status: DISABLED
Enforce: ENFORCE_ALL
Block: Y
Quantidade de SQLs permitidos: 3
[oracle@oracle26ai ~]$

7. Conferir a política antes de ativar

Repita no destino as consultas da etapa 3. Compare SQL_SIGNATURE, CURRENT_USER, TOP_LEVEL e objetos acessados; confira os contextos e TOP_LEVEL_ONLY. Verifique também a situação global do recurso:

SELECT * FROM dba_sql_firewall_status;
SELECT username, sql_signature, current_user, top_level,
accessed_objects
FROM dba_sql_firewall_allowed_sql
WHERE username = 'FW_DEMO_APP'
ORDER BY sql_signature;

Se o SQL Firewall global estiver desabilitado, sua ativação exige avaliar as demais políticas do container: DBMS_SQL_FIREWALL.ENABLE pode iniciar configurações já marcadas como habilitadas. Não trate essa operação global como parte automática da promoção de um único usuário.

8. Ativar em observação e testar a aplicação

Com o recurso global já habilitado e a política revisada, aplique a allowlist inicialmente sem bloqueio. Esse modo registra divergências, mas não impede a execução apenas por violação do SQL Firewall.

BEGIN
  DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST(
    username => 'FW_DEMO_APP',
    enforce  => DBMS_SQL_FIREWALL.ENFORCE_ALL,
    block    => FALSE
  );
END;
/

SQL> BEGIN DBMS_SQL_FIREWALL.ENABLE_ALLOW_LIST( username => 'FW_DEMO_APP', enforce => DBMS_SQL_FIREWALL.ENFORCE_ALL, block => FALSE ); END; / 2 3 4 5 6 7 8 PL/SQL procedure successfully completed. SQL>

Abra novas conexões usando o caminho real da aplicação. Teste inicialização do pool, transações, consultas, relatórios, integrações e rotinas previstas para a versão. Lembrando que uma execução rápida da tela inicial não cobre processos de fechamento e cargas periódicas.

SELECT occurred_at, cause, firewall_action,
       ip_address, client_program, os_user, sql_text
FROM dba_sql_firewall_violations
WHERE username = 'FW_DEMO_APP'
AND occurred_at >= SYSTIMESTAMP - INTERVAL '1' HOUR ORDER BY occurred_at DESC;

9. Habilitar bloqueio após aprovação

BEGIN
  DBMS_SQL_FIREWALL.UPDATE_ALLOW_LIST_ENFORCEMENT(
    username => 'APP_USER',
    enforce  => DBMS_SQL_FIREWALL.ENFORCE_ALL,
    block    => TRUE
  );
END;
/

SELECT username, status, enforce, block
FROM dba_sql_firewall_allow_lists
WHERE username = 'APP_USER';

Resultado esperado: ENABLED, ENFORCE_ALL e BLOCK = Y. Um SQL de teste previamente definido, sintaticamente válido e com privilégios suficientes, mas fora da política, deve ser bloqueado com ORA-47605. Os fluxos autorizados devem continuar funcionando. Execute os testes negativos primeiro em laboratório, com operações sem efeito destrutivo.

10. E quando produção já possui uma allowlist?

Nesse cenário, a importação é uma atualização por mesclagem. Não reutilize o procedimento de primeira importação sem revisar o resultado efetivo.

  • Exporte uma baseline da política de produção, preservando SQLs, contextos e configurações; guarde também uma relação consultável das entradas. Para esse backup, não desabilite a proteção apenas para reutilizar o script de transporte deste artigo.
  • Reproduza a baseline de produção em um ambiente de validação e aplique o novo artefato sobre ela. Confira o resultado da união, inclusive SQLs e endpoints antigos que continuarão permitidos.
  • Compare TOP_LEVEL_ONLY e a presença de capturas. Resolva diferenças e conflitos antes da mudança.
  • Revise os acréscimos e as remoções pretendidas separadamente: importar uma lista menor não revoga as entradas ausentes nela.
  • Defina explicitamente a estratégia de teste. O estado ENABLED/BLOCK do destino permanece; não suponha que o modo de observação da origem será aplicado.

Para uma política de destino já ativa em bloqueio, os novos SQLs podem passar a ser autorizados assim que forem mesclados. Trate isso como mudança de segurança e mantenha o escopo aprovado.

11. Retorno operacional e reversão da política

Se houver bloqueio indevido, um retorno operacional possível, mediante aprovação, é voltar apenas o usuário afetado ao modo sem bloqueio:

BEGIN
  DBMS_SQL_FIREWALL.UPDATE_ALLOW_LIST_ENFORCEMENT(
    username => 'APP_USER',
    enforce  => DBMS_SQL_FIREWALL.ENFORCE_ALL,
    block    => FALSE
  );
END;
/

Esse comando reduz a proteção do usuário e não desfaz a importação. Deve ser temporário e acompanhado de monitoramento.

Reimportar o JSON anterior também não remove os SQLs e contextos adicionados por uma mesclagem. Para restaurar exatamente a baseline, planeje a remoção das entradas específicas pelas APIs de manutenção ou a reconstrução da política em janela controlada. Uma reconstrução envolve desabilitar e excluir a allowlist antes da restauração, criando um intervalo sem enforcement; por isso, não deve ser automatizada como um rollback genérico.

Referências

Comentários