Este artigo faz parte da série “Jornada Oracle FreeStack”. No artigo anterior, exploramos o poder do banco convergente da Oracle com JSON nativo. Se você está chegando agora, recomendo começar pela Etapa 0 para configurar sua infraestrutura gratuita.
No post anterior, conectamos nossa API Quarkus ao banco de dados Oracle 26ai. No entanto, deixamos uma vulnerabilidade clássica: a senha do banco estava em texto puro no arquivo .env. Em um ambiente profissional, isso é um risco.
Hoje, vamos elevar o nível de segurança para o padrão Zero Trust. O objetivo não é necessariamente eliminar o arquivo .env, mas sim garantir que ele contenha apenas identificadores (OCIDs) e nunca segredos. Utilizaremos o OCI Vault com proteção via hardware (HSM) para que a senha real nunca toque o nosso disco local.
Identificadores vs. Segredos: O que pode ficar no .env?
No modelo Zero Trust, tratamos a configuração da seguinte forma:
- O Identificador (OCID): É o “endereço” do recurso na nuvem. Saber o OCID de um segredo é como saber o endereço de uma agência bancária: você sabe onde ela fica, mas isso não te dá a chave do cofre. Por isso, manter o OCID no
.envé aceitável. - O Segredo (Senha): É o valor que dá acesso real aos dados. Este valor nunca deve tocar o seu disco ou ser injetado como string no ambiente.
Comparativo de Segurança: Entendendo os Riscos
Para visualizar melhor o ganho de segurança, comparamos três abordagens comuns:
| Critério | 1. Arquivo .env (Senha Fixa) | 2. Variáveis de Ambiente (SO) | 3. OCI Vault (Zero Trust) |
|---|---|---|---|
| Onde a senha vive? | Disco: Gravada em texto puro no arquivo. | Memória/SO: Injetada no processo do sistema operacional. | HSM: Hardware de segurança isolado na nuvem. |
| Se o projeto vazar (Git)? | 🚨 Crítico: O invasor tem a senha do banco imediatamente. | ⚠️ Médio: A senha não está no código, mas pode estar em scripts de CI/CD. | ✅ Seguro: Vaza apenas o ID (OCID). Sem autenticação IAM, é inútil. |
| Se o servidor for invadido? | Basta ler o arquivo .env para roubar a senha. | Basta listar as variáveis do processo (env ou /proc). | A senha só existe na memória da aplicação, nunca no sistema de arquivos. |
| Auditoria | Nenhuma. Você não sabe quem leu o arquivo. | Nenhuma. | Total: O Vault registra quem, quando e de onde a senha foi solicitada. |
Ao usar o Vault, transformamos um risco de confidencialidade (vazar a senha) em um desafio de identidade (autenticar a aplicação). É muito mais fácil proteger e revogar uma identidade do que caçar uma senha vazada na internet.
É Grátis? (Limites do Always Free)
Muitos desenvolvedores evitam serviços de segurança “Enterprise” por medo de custos ocultos. O Oracle Cloud oferece uma camada Always Free generosa para o Vault:
- 20 Versões de Chaves Mestras (Master Encryption Keys): Protegidas por Hardware (HSM), o que custaria milhares de dólares em outros provedores.
- 150 Segredos (Secrets): Capacidade mais do que suficiente para armazenar senhas de banco, tokens de API e chaves privadas para múltiplos projetos pessoais.
Passo 1: Configuração da Identidade (OCI CLI)
Configuramos a OCI CLI para estabelecer a confiança entre nosso ambiente local e a nuvem. Antes de rodar o comando de configuração, você precisará coletar algumas informações no Console da Oracle:
1.1. Coletando os Identificadores (OCIDs)
O CLI pedirá três informações vitais. Localize-as antes de começar:
- Tenancy OCID: Clique no ícone de “boneco” (Perfil) no canto superior direito -> Clique em Tenancy: [SeuNome]. Copie o OCID (começa com
ocid1.tenancy...). - User OCID: Clique novamente no Perfil -> User Settings. Copie o OCID (começa com
ocid1.user...). - Region: Verifique o nome da sua região no topo da página (ex:
sa-saopaulo-1ouus-ashburn-1).
1.2. Instalação e Setup
Com os dados em mãos, instale e configure a CLI. Durante o processo setup config, responda Y (Yes) para gerar um novo par de chaves RSA.
# Instalação automatizada (Linux/Unix)
bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"
# Configuração interativa (Tenha os OCIDs em mãos!)
oci setup config
1.3. O Aperto de Mão (Upload da Chave Pública)
Ao final do setup, o terminal mostrará a Public Key Fingerprint e o caminho do arquivo oci_api_key_public.pem.
- Copie o conteúdo desse arquivo
.pem. - Volte ao Console OCI, em User Settings > API Keys.
- Clique em Add API Key > Paste Public Key e cole o conteúdo.
- Clique em Add.
1.4. Ajuste Crítico: Automação (Passphrase)
Para que o Quarkus consiga iniciar sem travar pedindo senha no terminal, precisamos garantir que a autenticação seja silenciosa. Edite seu arquivo de configuração:
nano ~/.oci/config
Verifique a linha pass_phrase:
- Se você criou uma senha para a chave: Adicione a linha
pass_phrase=SuaSenhaSecreta. - Se você NÃO criou senha (Enter vazio): Remova completamente a linha
pass_phrase.
Sem isso, a aplicação falhará ao tentar conectar no Vault durante o boot.
Passo 2: O Cofre, a Chave e o Segredo no Console OCI
- Criar o Vault: Vá em Identidade e Segurança > Vault. Crie o
FreeStack-Vault. - Criar a Chave Mestra: Dentro do cofre, em Recursos > Chaves de Criptografia Principais, crie a
FreeStack-Master-Keycom HSM. - Criar o Segredo: Vá em Identidade e Segurança > Gerenciamento de Segredos. Crie o segredo
db-passwordvinculado à chave HSM. - OCID: Copie o OCID do Segredo (prefixo
ocid1.vaultsecret).
Passo 3: Implementação no Quarkus
3.1. Dependências (pom.xml)
Adicionamos o SDK da Oracle e o suporte a credenciais do Quarkus:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-credentials</artifactId>
</dependency>
<dependency>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-secrets</artifactId>
<version>3.54.0</version>
</dependency>
<dependency>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-common-httpclient-jersey3</artifactId>
<version>3.54.0</version>
</dependency>
3.2. OciVaultService.java
Este serviço gerencia a conexão e a recuperação do segredo através do OCI SDK.
@ApplicationScoped
public class OciVaultService {
private static final Logger LOG = Logger.getLogger(OciVaultService.class);
@ConfigProperty(name = "oci.secret.ocid")
Optional<String> secretOcid;
@ConfigProperty(name = "oci.auth.instance-principal", defaultValue = "false")
boolean useInstancePrincipal;
public String getSecretValue() {
if (secretOcid.isEmpty() || secretOcid.get().startsWith("ocid1.vaultsecret.oc1.xxx")) {
throw new RuntimeException("CRITICAL ERROR: OCI Secret OCID is not configured.");
}
LOG.info("Retrieving secret from OCI Vault: " + secretOcid.get());
try (SecretsClient secretsClient = createSecretsClient()) {
GetSecretBundleRequest getSecretBundleRequest = GetSecretBundleRequest.builder()
.secretId(secretOcid.get())
.build();
GetSecretBundleResponse getSecretBundleResponse = secretsClient.getSecretBundle(getSecretBundleRequest);
Base64SecretBundleContentDetails contentDetails = (Base64SecretBundleContentDetails)
getSecretBundleResponse.getSecretBundle().getSecretBundleContent();
byte[] decodedBytes = Base64.getDecoder().decode(contentDetails.getContent());
return new String(decodedBytes);
} catch (Exception e) {
LOG.error("Error retrieving secret from OCI Vault", e);
throw new RuntimeException("Could not retrieve secret from OCI Vault.", e);
}
}
private SecretsClient createSecretsClient() throws Exception {
BasicAuthenticationDetailsProvider provider;
if (useInstancePrincipal) {
provider = InstancePrincipalsAuthenticationDetailsProvider.builder().build();
} else {
ConfigFileReader.ConfigFile configFile = ConfigFileReader.parseDefault();
provider = new ConfigFileAuthenticationDetailsProvider(configFile);
}
return SecretsClient.builder().build(provider);
}
}
3.3. OciVaultCredentialsProvider.java
Este é o componente que integra o Vault ao ecossistema Quarkus. Ao implementar CredentialsProvider, permitimos que o Quarkus gerencie o ciclo de vida da credencial.
@ApplicationScoped
@Named("oci-vault-provider")
public class OciVaultCredentialsProvider implements CredentialsProvider {
@Inject
OciVaultService vaultService;
@Override
public Map<String, String> getCredentials(String credentialsProviderName) {
Map<String, String> credentials = new HashMap<>();
String password = vaultService.getSecretValue();
credentials.put(PASSWORD_PROPERTY_NAME, password);
return credentials;
}
}
Wallet vs Vault: Onde termina um e começa o outro?
Uma dúvida comum nesta etapa é: “Se estou usando o Vault para a senha, ainda preciso da Wallet?”
A resposta curta é sim. Eles resolvem problemas diferentes:
- Wallet (Camada de Transporte): Trata do Mutual TLS (mTLS). Ela contém os certificados que garantem que o “tubo” entre seu Java e a Oracle Cloud seja criptografado e autêntico. Sem a Wallet, você não consegue nem chegar na “porta” do banco.
- Vault (Camada de Autenticação): Trata das Credenciais. Ele guarda a “chave” (senha do ADMIN) que abre o banco. Sem o Vault, você teria que deixar essa chave debaixo do tapete (seu arquivo
.env).
A Vantagem Real: Ao separar os dois, você cria uma defesa em profundidade. Se alguém roubar seu código e sua Wallet, eles ainda não têm a senha. E mesmo que adivinhassem a senha, precisariam da sua Chave de API da OCI para acessar o Vault. É o padrão ouro de segurança em nuvem.
O Elo de Ligação: Como tudo se encaixa?
Você deve estar se perguntando: Como o banco de dados sabe que deve chamar esse código?
A mágica acontece no application.properties. Quando definimos quarkus.datasource.credentials-provider, o Quarkus altera seu ciclo de vida de inicialização:
- Boot: O Quarkus inicia e vê que o Datasource exige um provedor de credenciais.
- Lookup: Ele procura pelo CDI Bean com o nome
@Named("oci-vault-provider"). - Request: O Quarkus chama o método
getCredentials(). - OCI Call: Nosso código vai até a Oracle Cloud, acessa o HSM e traz a senha.
- Injection: O Quarkus recebe a senha em memória e a injeta no pool de conexões (Agroal).
- Ready: O banco de dados conecta e a aplicação sobe.
# Ativa o provedor de credenciais dinâmico
quarkus.datasource.credentials-provider=oci-vault-provider
# Configurações do Vault
oci.secret.ocid=${OCI_SECRET_OCID}
oci.auth.instance-principal=${OCI_INSTANCE_PRINCIPAL:false}
Conclusão: Segurança Absoluta
Ao remover o fallback do .env, forçamos uma cultura de segurança rigorosa. Agora, a senha do seu banco de dados reside exclusivamente dentro de um hardware criptográfico na nuvem e só é acessada por identidades autorizadas.
No próximo artigo, daremos um passo além: OCI Object Storage.
