kisenon
Agent-Safe Change Control

Forks enmascarados

Dé a un agente (o a un humano) la forma de producción y nada de su PII — políticas de enmascaramiento, la biblioteca de funciones integradas y cómo las ramas y los sandboxes enmascarados permanecen sellados hasta que el enmascaramiento se confirma.

MASK es el track de Agent-Safe Change Control para datos sensibles: entrega a un agente un fork con la forma de producción y nada de su PII. Funciona de dos maneras — ramas enmascaradas (para humanos: dev, CI, contratistas) y sandboxes enmascarados (para agentes). Ambas se cubren a continuación.

El enmascaramiento de datos anonimiza las columnas sensibles en el momento en que se crea una rama. Se adjunta una política de enmascaramiento a la llamada de creación de rama, y las columnas coincidentes de la nueva rama se reescriben de forma irreversible — con hash, anuladas, truncadas o reemplazadas — antes de que la rama sea siquiera accesible. La rama padre nunca se modifica.

Recurriría a ello para entregar datos con forma de producción a desarrollo, CI o un contratista sin entregar la PII que contienen: formas de tabla reales, recuentos de filas reales, correos electrónicos falsos.

Cómo funciona

Una política de enmascaramiento es un conjunto de reglas con nombre y alcance de proyecto. Cada regla hace coincidir columnas por patrón y nombra una función de enmascaramiento integrada:

CampoSignificado
schema_patternPatrón de nombre de esquema (% o * = cualquiera, _ = un carácter). El valor por defecto es *.
table_patternPatrón de nombre de tabla.
column_patternPatrón de nombre de columna.
masking_fnUna de las funciones integradas de abajo.
fn_argsArgumentos de la función (solo mask_constant toma uno: value).

En el momento de la creación de la rama, cuando se proporciona un masking_policy_id:

  1. La rama se bifurca de su padre como de costumbre (copy-on-write — instantáneo).
  2. La rama entra en el estado masking. No se aprovisiona ningún endpoint y el proxy rechaza las conexiones a ella: no hay ninguna ventana en la que se puedan leer los datos previos al enmascaramiento.
  3. Un worker de enmascaramiento se conecta a la compute de la rama como un rol de mínimo privilegio, descubre el esquema, hace coincidir sus reglas con él y ejecuta cada reescritura en una sola transacción.
  4. La rama aterriza en ready y sus endpoints se levantan — ahora sirviendo solo datos enmascarados. Ante cualquier fallo, la rama aterriza en failed y permanece sellada; elimínela y reinténtela.

Las entradas de las reglas se tratan como datos, nunca como SQL: los identificadores se entrecomillan y los valores de los argumentos se vinculan como parámetros en la ejecución, de modo que un nombre de columna o una constante hostil no puede escapar de la reescritura.

Funciones integradas

FunciónEfecto
mask_emailmd5(value)@masked.invalid
mask_nameName_ + un prefijo de hash de 8 caracteres
mask_nullNULL (la columna debe admitir nulos)
mask_constantUn valor fijo que usted proporciona (fn_args.value)
mask_ssn_partial***-**-1234 — conserva los últimos 4 dígitos
mask_credit_card****-****-****-1234 — conserva los últimos 4 dígitos
mask_ip0.0.0.0
mask_date_yearConserva el año, trunca al 1 de enero
mask_hashmd5(value)
mask_shuffleMezcla basada en hash (la mezcla completa de caracteres está planificada)
mask_phoneUn número sintético +1-555-XXXX
mask_uuidUn UUID aleatorio nuevo

El catálogo también lo sirve la API:

curl -s https://api.kisenon.com/v1/masking-functions \
  -H "Authorization: Bearer $KISENON_API_KEY"

Gestión de políticas

En la consola, abra Project settings → Data masking para crear una política: póngale nombre, añada reglas (columnas de patrón + un desplegable de función) y guarde. La misma superficie existe en la API:

curl -s -X POST \
  https://api.kisenon.com/v1/projects/$PROJECT_ID/masking-policies \
  -H "Authorization: Bearer $KISENON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "dev-safe",
    "rules": [
      {"table_pattern": "users", "column_pattern": "email", "masking_fn": "mask_email"},
      {"table_pattern": "users", "column_pattern": "phone", "masking_fn": "mask_null"},
      {"table_pattern": "%", "column_pattern": "%ssn%", "masking_fn": "mask_ssn_partial"}
    ]
  }'

Luego cree una rama enmascarada añadiendo la política a una llamada normal de creación de rama:

curl -s -X POST \
  https://api.kisenon.com/v1/projects/$PROJECT_ID/branches \
  -H "Authorization: Bearer $KISENON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "masked-dev", "masking_policy_id": "'$POLICY_ID'"}'

La rama informa state: "masking" mientras se ejecuta la reescritura; obsérvela cambiar a ready en la consola (en vivo, a través del flujo de eventos del proyecto) o sondeando GET /v1/branches/{id}.

Sandboxes enmascarados (para agentes)

Las mismas políticas enmascaran el fork del sandbox de un agente, de modo que un agente trabaja contra la forma de producción y nunca ve su PII. Adjunte una política en la creación:

keon sandbox create --project <id> --masking-policy <policy-id>

El enmascaramiento se ejecuta antes de que el sandbox se active. El sandbox informa masked: true y su masking_policy_id, y mientras sigue en creating un objeto de progreso masking (state, phase, rules_total, rules_completed, rows_affected_so_far, error) muestra la reescritura avanzando.

Establezca un mínimo por proyecto para que cada sandbox quede enmascarado por defecto:

keon projects update <id> --sandbox-masking-policy <policy-id>   # or: none

Un --masking-policy por solicitud anula el valor por defecto del proyecto, pero nunca puede excluirse de un mandato — una defensa contra un agente que se libra del enmascaramiento con labia. Establecer el mandato es solo para propietario/administrador; las claves con capacidad de agente se rechazan (403).

Fallo cerrado por construcción. Los endpoints de un fork enmascarado nacen en un estado de enmascaramiento — el proxy rechaza las conexiones (SQLSTATE 57P05) hasta que la reescritura se confirma. Si el paso de enmascaramiento falla o no está conectado, la creación falla cerrada: nunca se emite una URL para un fork sin enmascarar. El worker de enmascaramiento se conecta como el rol de mínimo privilegio kisenon_masker (nunca un superusuario), no posee ningún RBAC de clúster, y su contraseña por ejecución nunca se persiste ni se registra.

Dos salvedades que conviene conocer:

  • El DML contra valores enmascarados no coincidirá en el padre durante la reproducción. Una sentencia como UPDATE … WHERE email = 'a1b2@masked.invalid' apunta a un valor enmascarado que no existe en main. El trabajo de carril de esquema es independiente del valor y se promociona limpiamente; el DML dependiente del valor no es tarea para un fork enmascarado.
  • Las claves foráneas siguen aplicándose. El enmascaramiento deshabilita los triggers de usuario (ALTER TABLE … DISABLE TRIGGER USER), no los triggers de integridad referencial. Enmascarar una columna dentro de una relación de clave foránea puede, por tanto, provocar un error de RI y hacer fallar el fork cerrado en lugar de romper la referencia en silencio.
  • v1 enmascara solo la base de datos main.

Conviene saber

  • El enmascaramiento es de una sola vez, en la creación. Editar una política nunca toca las ramas que ya se crearon con ella — conservan la forma de datos con la que nacieron. Vuelva a crear la rama para aplicar las nuevas reglas.
  • Una política en uso no se puede eliminar. Eliminar una política con la que se creó una rama activa devuelve 409 policy_in_use; elimine primero esas ramas.
  • Las reglas sin coincidencia se omiten, no son fatales. Si su esquema se desvió y un patrón no coincide con nada, la rama igualmente se completa — revise los patrones de las reglas si una columna que esperaba enmascarada todavía tiene una forma de datos real.
  • Las discrepancias de tipo hacen fallar la rama. Una regla que coincide con una columna que su función no puede reescribir (digamos mask_email sobre un integer) aborta todo el enmascaramiento — la rama aterriza en failed y nunca se expone enmascarada a medias.