Como encriptar dados sensíveis em Databricks: passo a passo
Este tutorial mostra como encriptar colunas com dados sensíveis (PII) em Databricks usando PySpark e AES simétrico, para reduzir o risco de exposição em ambientes de desenvolvimento e reporting. Encriptar antes de persistir ou partilhar dados ajuda a cumprir requisitos de segurança e privacidade, e a limitar o blast radius em caso de acesso indevido.
Pré-requisitos
- Workspace Databricks com um cluster activo (ex.: 2 a 8 nós dependendo do volume) e permissões para criar notebooks.
- Permissões para ler/escrever tabelas/ficheiros (mounts ou armazenamento do Azure/ADLS/Blob).
- Familiaridade básica com PySpark e DataFrame; conhecimento mínimo de UDFs.
- Chave de encriptação (pode ser gerada para testes; em produção use Azure Key Vault ou CMK via Databricks).
- Biblioteca cryptography instalada no cluster: em notebooks use %pip install cryptography ou instale como Library no cluster.
Passo 1: Porquê e como escolher encriptação
Encriptar colunas protege dados em repouso e em movimento. Aqui usamos AES-256 em modo GCM (autenticado) para garantir confidencialidade e integridade (detecta corrupção/tamper). AES-GCM adiciona um tag de 16 bytes e usa um nonce de 12 bytes por mensagem. Em termos práticos, uma string de 20 bytes resulta tipicamente numa saída encriptada de ~48 bytes antes do base64; o base64 aumenta o tamanho final em cerca de 33% — convém dimensionar armazenamento e índices de acordo.
Para produção: nunca coloque chaves no código. Use Azure Key Vault integrado com Databricks Secrets ou Customer-Managed Keys (CMK) para encriptação ao nível do armazenamento. A política de acesso deve seguir o princípio do menor privilégio. Para auditoria, combine com Unity Catalog para lista de controlo de acessos e com logs de acesso do storage.
Passo 2: Preparar um notebook PySpark e gerar/definir chave
Crie um notebook Python em Databricks. Para testes pode definir a chave inline (32 bytes para AES-256). Em ambiente real, recupere a chave via Databricks Secrets ou Key Vault (por exemplo: dbutils.secrets.get).
from pyspark.sql import SparkSession
from pyspark.sql.functions import col
spark = SparkSession.builder.getOrCreate()
# Chave de 32 bytes para AES-256 (APENAS EXEMPLO para desenvolvimento)
encryption_key = b"0123456789abcdef0123456789abcdef" # 32 bytes
# Em produção: key = dbutils.secrets.get(scope='myScope', key='enc-key')
Passo 3: Funções de encriptação/desencriptação em Python
Vamos usar a biblioteca cryptography para AES-GCM. Instale-a no cluster com %pip install cryptography ou adicione como Library. As funções retornam base64 para armazenamento directo em colunas string.
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os, base64
def encrypt_value(plaintext: str, key: bytes) -> str:
aesgcm = AESGCM(key)
nonce = os.urandom(12) # 96-bit nonce (requerido para GCM)
ct = aesgcm.encrypt(nonce, plaintext.encode('utf-8'), None)
# armazenamos nonce + ciphertext+tag juntos e fazemos base64
return base64.b64encode(nonce + ct).decode('utf-8')
def decrypt_value(token_b64: str, key: bytes) -> str:
data = base64.b64decode(token_b64)
nonce, ct = data[:12], data[12:]
aesgcm = AESGCM(key)
return aesgcm.decrypt(nonce, ct, None).decode('utf-8')
Passo 4: Exemplo de DataFrame com dados sensíveis
Crie um DataFrame de exemplo com nomes e emails. Para testar performance, experimente 10k, 100k ou 1M linhas e meça tempo. Um exemplo rápido com 2 linhas:
data = [
(1, 'Alice', 'alice@example.com'),
(2, 'Bob', 'bob@example.com'),
]
columns = ['id', 'name', 'email']
df = spark.createDataFrame(data, columns)
df.show()
Passo 5: Aplicar encriptação em coluna com UDF
Usamos um UDF para aplicar encrypt_value a cada linha. Atenção: UDFs em Python implicam overhead—para 100k linhas num cluster modesto pode demorar dezenas de segundos; para 1M linhas conte minutos dependendo dos recursos. Se a performance for crítica, considere encriptar na layer de ingestão (stream nativo), em UDFs em C/Scala, ou usar funcionalidades nativas do storage.
from pyspark.sql.functions import udf
from pyspark.sql.types import StringType
encrypt_udf = udf(lambda s: encrypt_value(s, encryption_key), StringType())
df_encrypted = df.withColumn('email_encrypted', encrypt_udf(col('email'))).drop('email')
df_encrypted.show(truncate=False)
Passo 6: Persistir dados encriptados
Guarde o DataFrame encriptado como Delta ou Parquet. Lembre-se que a coluna encriptada é uma string base64 e ocupa mais espaço. Em produção combine com encriptação ao nível de disco (storage encryption) e use Unity Catalog para controlar acessos à tabela. Exemplo de escrita:
df_encrypted.write.mode('overwrite').format('delta').save('/mnt/data/encrypted_users.delta')
# ou salvar como tabela
# df_encrypted.write.mode('overwrite').saveAsTable('encrypted_users')
Passo 7: Desencriptar para uso autorizado
Para ler e desencriptar, carregue os dados e aplique um UDF de desencriptação apenas em sessões autorizadas. Proteja a chave no runtime e limite quem pode correr esse notebook. Uma sessão autorizada pode desencriptar apenas as colunas necessárias.
decrypt_udf = udf(lambda s: decrypt_value(s, encryption_key), StringType())
df_loaded = spark.read.format('delta').load('/mnt/data/encrypted_users.delta')
df_decrypted = df_loaded.withColumn('email', decrypt_udf(col('email_encrypted'))).drop('email_encrypted')
df_decrypted.show()
Verificar o resultado
Confirme que o ficheiro/tabela contém apenas a coluna encriptada (por exemplo inspecione com df_encrypted.columns). Teste a desencriptação com entradas de diferentes comprimentos e caracteres (UTF-8). Verifique erros comuns: chave inválida (ex.: tamanho errado), dados truncados (base64 inválido) ou nonce corrompido. Faça testes de performance: cronometre encriptação de 10k/100k/1M linhas e registe CPU/memória para dimensionar o cluster.
Conclusão
Agora sabe como encriptar e desencriptar colunas em Databricks usando PySpark e AES-GCM. Próximos passos recomendados: integrar com Azure Key Vault/Databricks Secrets ou CMK para gestão de chaves; usar Unity Catalog para controlo de acessos; e avaliar alternativas de performance (encriptação na ingestão ou UDFs em Scala). Dica final: evite colocar chaves em notebooks — use secrets para reduzir risco e manter rastreabilidade das operações.