Cómo encriptar datos sensibles en Databricks: paso a paso
Este tutorial muestra cómo encriptar columnas con datos sensibles (PII) en Databricks usando PySpark y AES simétrico, para reducir el riesgo de exposición en entornos de desarrollo y reporting. Encriptar antes de persistir o compartir datos ayuda a cumplir requisitos de seguridad y privacidad, y a limitar el blast radius en caso de acceso indebido.
Prerequisitos
- Workspace Databricks con un cluster activo (ej.: 2 a 8 nodos dependiendo del volumen) y permisos para crear notebooks.
- Permisos para leer/escribir tablas/archivos (mounts o almacenamiento de Azure/ADLS/Blob).
- Familiaridad básica con PySpark y DataFrame; conocimiento mínimo de UDFs.
- Clave de encriptación (puede generarse para pruebas; en producción use Azure Key Vault o CMK vía Databricks).
- Biblioteca cryptography instalada en el cluster: en notebooks use %pip install cryptography o instale como Library en el cluster.
Paso 1: Por qué y cómo elegir encriptación
Encriptar columnas protege datos en reposo y en movimiento. Aquí usamos AES-256 en modo GCM (autenticado) para garantizar confidencialidad e integridad (detecta corrupción/manipulación). AES-GCM añade una etiqueta (tag) de 16 bytes y usa un nonce de 12 bytes por mensaje. En términos prácticos, una cadena de 20 bytes resulta típicamente en una salida encriptada de ~48 bytes antes del base64; el base64 aumenta el tamaño final en alrededor de un 33% — conviene dimensionar almacenamiento e índices en consecuencia.
Para producción: nunca coloque claves en el código. Use Azure Key Vault integrado con Databricks Secrets o Customer-Managed Keys (CMK) para encriptación a nivel de almacenamiento. La política de acceso debe seguir el principio del menor privilegio. Para auditoría, combine con Unity Catalog para listas de control de acceso y con logs de acceso del storage.
Paso 2: Preparar un notebook PySpark y generar/definir clave
Creé un notebook Python en Databricks. Para pruebas puede definir la clave inline (32 bytes para AES-256). En entorno real, recupere la clave vía Databricks Secrets o Key Vault (por ejemplo: 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')
Paso 3: Funciones de encriptación/desencriptación en Python
Vamos a usar la biblioteca cryptography para AES-GCM. Instálela en el cluster con %pip install cryptography o añádala como Library. Las funciones devuelven base64 para almacenamiento directo en columnas 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')
Paso 4: Ejemplo de DataFrame con datos sensibles
Creé un DataFrame de ejemplo con nombres y emails. Para probar rendimiento, experimente con 10k, 100k o 1M filas y mida tiempo. Un ejemplo rápido con 2 filas:
data = [
(1, 'Alice', 'alice@example.com'),
(2, 'Bob', 'bob@example.com'),
]
columns = ['id', 'name', 'email']
df = spark.createDataFrame(data, columns)
df.show()
Paso 5: Aplicar encriptación en columna con UDF
Usamos un UDF para aplicar encrypt_value a cada fila. Atención: los UDFs en Python implican overhead—para 100k filas en un cluster modesto puede tardar decenas de segundos; para 1M filas cuente minutos dependiendo de los recursos. Si el rendimiento es crítico, considere encriptar en la capa de ingestión (stream nativo), en UDFs en C/Scala, o usar funcionalidades nativas del 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)
Paso 6: Persistir datos encriptados
Guarde el DataFrame encriptado como Delta o Parquet. Recuerde que la columna encriptada es una string base64 y ocupa más espacio. En producción combine con encriptación a nivel de disco (storage encryption) y use Unity Catalog para controlar accesos a la tabla. Ejemplo de escritura:
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')
Paso 7: Desencriptar para uso autorizado
Para leer y desencriptar, cargue los datos y aplique un UDF de desencriptación solo en sesiones autorizadas. Proteja la clave en el runtime y limite quién puede ejecutar ese notebook. Una sesión autorizada puede desencriptar solo las columnas necesarias.
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 el resultado
Confirme que el archivo/tabla contiene solo la columna encriptada (por ejemplo inspeccione con df_encrypted.columns). Pruebe la desencriptación con entradas de diferentes longitudes y caracteres (UTF-8). Verifique errores comunes: clave inválida (ej.: tamaño incorrecto), datos truncados (base64 inválido) o nonce corrupto. Haga pruebas de rendimiento: cronometre la encriptación de 10k/100k/1M filas y registre CPU/memoria para dimensionar el cluster.
Conclusión
Ahora sabe cómo encriptar y desencriptar columnas en Databricks usando PySpark y AES-GCM. Próximos pasos recomendados: integrar con Azure Key Vault/Databricks Secrets o CMK para gestión de claves; usar Unity Catalog para control de accesos; y evaluar alternativas de rendimiento (encriptación en la ingestión o UDFs en Scala). Consejo final: evite poner claves en notebooks — use secrets para reducir riesgo y mantener trazabilidad de las operaciones.