Implementa una solución para migrar datos sensibles

En este documento, se muestra cómo implementar el patrón de referencia Migra datos sensibles en BigQuery mediante Dataflow y Cloud Data Loss Prevention a fin de resolver algunos de los desafíos clave para migrar y procesar datos sensibles para casos de uso de estadísticas en tiempo real.

Descripción general

Para usar las funciones avanzadas de datos y estadísticas que están disponibles a través de los servicios en línea, muchas organizaciones migran plataformas de datos locales a la nube. Esto a menudo incluye la migración de datos sensibles, como números de tarjetas de crédito, antecedentes e identificadores médicos, y números de identificación de vehículos (VIN). El patrón de referencia Migra datos sensibles en BigQuery mediante Dataflow y Cloud Data Loss Prevention puede ayudarte a migrar conjuntos de datos grandes que contengan este tipo de datos sensibles.

En este artículo, encontrarás un recorrido a través del patrón de referencia. Se analizan los detalles clave de diseño e implementación que pueden ayudarte a implementar el patrón en tu organización.

Tareas de migración de datos

Este patrón aborda las siguientes tareas clave de migración de datos:

  • Inspeccionar conjuntos de datos a escala de petabytes para ver si contienen información sensible
  • Migrar y desidentificar los datos sensibles
  • Reidentificar los resultados desidentificados para habilitar las aplicaciones descendentes que requieren los datos originales.

Desidentificación de datos

La desidentificación transforma los datos sensibles para que puedas seguir usándolos mientras reduces el riesgo de exposición. Esta transformación usa métodos no reversibles como hashing criptográfico y enmascaramiento, y métodos reversibles como encriptación determinista.

Por ejemplo, considera cómo podrías analizar un problema que afecta a varias cuentas de clientes sin exponer la información de identificación personal (PII). Si usas la desidentificación, puedes ocultar estos datos y, al mismo tiempo, conservar la capacidad de trabajar con ellos.

Compara las tablas que aparecen a continuación:

Comparación de dos tablas, una con datos sensibles y otra con datos desidentificados.

En la tabla de la izquierda, se muestra la PII. En la tabla desidentificada de la derecha, estos datos sensibles están ocultos, pero aún puedes ver que los valores de account_id en las filas 1 y 3 son los mismos, mientras que los correos electrónicos son diferentes. Además, puedes tener una idea del rango de edad de la persona sin exponer la edad específica.

Arquitectura del patrón de referencia

El patrón de referencia te permite compilar una canalización de procesamiento automatizado que puedes usar para realizar las tareas de migración de datos.

La arquitectura del patrón se ilustra en el siguiente diagrama:

Una ilustración que muestra los productos que usa el patrón y cómo fluye el trabajo entre ellos.

Un grafo acíclico dirigido (DAG) para una canalización implementada es similar al siguiente:

Un grafo acíclico dirigido (DAG) para una canalización creada mediante la implementación del patrón.

Especifica fuentes de datos

El patrón de referencia admite la transferencia de datos de diferentes fuentes. Puedes importar tus datos en Cloud Storage o puedes dejarlos en su ubicación original si es necesario por motivos de cumplimiento o de costo. En ese caso, puedes procesar los datos donde se encuentren, ya sea de forma local o en otra nube.

El patrón de referencia se implementa mediante el framework de código abierto de Apache Beam, por lo que puedes elegir ejecutar la canalización con cualquiera de los ejecutores disponibles de Beam. También puedes integrar una variedad de fuentes de datos mediante diferentes transformaciones de E/S de Beam. Esto te permite cargar datos desde un bucket de Amazon S3 o extender el patrón para trabajar con otros conectores según sea necesario. Este enfoque flexible también te permite usar el producto de asignación de token de datos que mejor se adapte a tus necesidades.

Procesa archivos de datos

El patrón de referencia te permite procesar datos en varios formatos, como CSV, Avro y JSON. Crea de forma automática un esquema de tabla adecuado en BigQuery mediante la función DynamicDestinations de Beam. Para el procesamiento de archivos CSV grandes, se usa DoFn divisible a fin de dividir el archivo por tamaño de bytes con un delimitador de líneas. En el siguiente fragmento de código, se ilustra este enfoque:

@ProcessElement
public void processElement(ProcessContext c, RestrictionTracker<OffsetRange, Long> tracker)
    throws IOException {
  String fileName = c.element().getKey();
  try (SeekableByteChannel channel = getReader(c.element().getValue())) {
    FileReader reader =
        new FileReader(
            channel, tracker.currentRestriction().getFrom(), recordDelimiter.getBytes());
    while (tracker.tryClaim(reader.getStartOfNextRecord())) {
      reader.readNextRecord();
      String contents = reader.getCurrent().toStringUtf8();
      String key = String.format("%s~%d", fileName, new Random().nextInt(keyRange));
      numberOfRowsRead.inc();
      c.outputWithTimestamp(KV.of(key, contents), Instant.now());
    }
  }
}

Si tu conjunto de datos contiene una gran cantidad de archivos pequeños, es posible que no necesites la fragmentación de archivos. Para este conjunto de datos, puedes usar la transformación ContextualTextIO y la información de los metadatos, como el nombre del archivo y el número de fila para hacer un seguimiento y generar informes. En los siguientes fragmentos de código, se ilustra este enfoque:

case CSV:
  records =
      inputFiles
          .apply(
              "SplitCSVFile",
              ParDo.of(
                  new CSVFileReaderSplitDoFn(
                      options.getKeyRange(),
                      options.getRecordDelimiter(),
                      options.getSplitSize())))
          .apply(
              "ConvertToDLPRow",
              ParDo.of(new ConvertCSVRecordToDLPRow(options.getColumnDelimiter(), header))
                  .withSideInputs(header));
  break;
@ProcessElement
public void processElement(ProcessContext context) throws IOException {
  Table.Row.Builder rowBuilder = Table.Row.newBuilder();
  Row nonTokenizedRow = context.element();
  String filename = Util.sanitizeCSVFileName(
      nonTokenizedRow.getLogicalTypeValue("resourceId", ResourceId.class).getFilename());
  String input = nonTokenizedRow.getString("value");
  LOG.debug("File Name: {} Value: {}", filename, input);
  List<String> csvHeader = context.sideInput(header);

Administra la latencia y la cuota

A medida que la canalización transfiere registros individuales, estos se agrupan en lotes pequeños mediante el BatchRequestForDLP de Beam. Un umbral configurable que debes especificar en bytes determina el tamaño del lote. Una vez que se alcanza el umbral de tamaño del lote, se envían los registros agrupados a la API de Cloud Data Loss Prevention en una sola solicitud. Luego, la API de DLP analiza todos los registros del lote enviado y muestra todos los resultados de ese lote en la respuesta.

El uso de lotes te permite reducir la cantidad de solicitudes a la API de DLP, lo que te ayuda a mantenerte dentro de tu asignación de cuota. También te permite aumentar la capacidad de procesamiento y reducir la latencia general mediante el procesamiento de varios lotes en paralelo.

Usa el parámetro de rango de claves

Para equilibrar la latencia con la cuota de la API de DLP, usa el parámetro de canalización --keyRange. Aumentar el valor de --keyrange aumenta la velocidad de procesamiento y disminuye la latencia, pero también usa más recursos, lo que hace que te acerques a los límites de uso más rápido.

Por ejemplo, cuando se probó el patrón de referencia, se procesó un archivo CSV de 400 MB que contenía 2 millones de filas con la configuración de canalización predeterminada de 5 trabajadores, un umbral de tamaño de lote de 0.5 MB y un rango de claves de 100. En la siguiente captura de pantalla, se muestra que la canalización se mantuvo dentro de la cuota de 10,000 llamadas por minuto de la API de DLP del proyecto y procesó correctamente el archivo en menos de 10 minutos:

Gráfico que muestra la capacidad de procesamiento de la canalización en comparación con la cuota.

Luego, procesamos estos datos más rápido mediante el aumento del parámetro de tamaño de la clave a 1,000. Esto requirió un máximo de 800 llamadas a la API (400 MB/0.5 MB = 800), que seguía siendo una cantidad menor que la cuota del proyecto de 10,000 llamadas a la API por minuto. En la siguiente captura de pantalla, puedes ver que los mismos datos se procesaron en menos de un minuto:

Gráfico que muestra la capacidad de procesamiento de la canalización cuando el tamaño de la clave se aumenta a 1,000

Los resultados de este análisis de comparativas dependen de los datos que se procesaron y de la configuración de Cloud DLP que se usó. Es posible que debas ajustar los parámetros de canalización adicionales disponibles en el patrón de referencia para ajustar el rendimiento en función de tus requisitos específicos.

Usa el parámetro de tamaño del lote

Cloud DLP proporciona un conjunto de tipos de información integrada llamados Infotipos. Algunos de los detectores de Infotipos, como DATE, DATE_OF_BIRTH, FIRST_NAME, LAST_NAME y LOCATION, pueden afectar la latencia de la operación. A fin de obtener un mejor rendimiento cuando se procesan solicitudes que contienen Infotipos sensibles a la latencia, reduce el valor del parámetro --batchSize para usar un tamaño de lote más pequeño. Esto garantiza que Cloud DLP procese las solicitudes en fragmentos pequeños y distribuidos. La compensación es que lleva más tiempo procesar las solicitudes.

Por ejemplo, inspeccionar 1 TB de datos para Infotipos no sensibles a la latencia mediante un tamaño de lote de 500 KB/carga útil tarda alrededor de 8 minutos. Inspeccionar esos mismos datos en busca de Infotipos sensibles a la latencia mediante un tamaño del lote de 50 KB por carga útil lleva unos 15 minutos.

Ejecuta la canalización mediante una plantilla flexible

El patrón de referencia usa una plantilla flexible de Dataflow para que puedas configurar la estructura de la canalización en el entorno de ejecución. Esto te permite volver a usar la misma canalización para diferentes fines. Los siguientes son ejemplos de cómo puedes activar la canalización para abordar diferentes casos de uso:

  • Para inspeccionar un archivo CSV en un bucket de Amazon S3, sigue estos pasos:

    --filePattern=s3://<myBucket>/file.csv --DLPMethod=INSPECT --awsRegion=<myAWSRegion> --awsCredentialsProvider=$AWS_CRED
    
  • Para desidentificar datos en un archivo de Avro en un bucket de Cloud Storage, haz lo siguiente:

    --filePattern=gs://<myBucket>/file.avro --DLPMethod=DEID
    
  • Para volver a identificar datos en BigQuery, sigue estos pasos:

    --tableRef=<myProjectId>:<myDataset>.<myTable> --queryPath=gs://<myBucket>/reid_query.sql"
    

Maneja la precisión de la inspección

Cuando realizas la inspección, es importante supervisar la exactitud de tus resultados mediante la validación de la cantidad de hallazgos que coinciden con tus datos de entrada. Aunque en la mayoría de los casos los Infotipos integrados de Cloud DLP proporcionan suficiente precisión, puedes mejorar aún más los resultados mediante Infotipos personalizados.

Un ejemplo de cuándo podrías querer hacer esto proviene de la industria de los servicios financieros. Algunas organizaciones de ese sector deben clasificar los números de tarjetas de crédito como internos o externos durante la inspección. Para solucionar este problema, puedes crear detectores de Infotipos personalizados con una expresión regular (regex) a fin de detectar coincidencias en función de un patrón para un conjunto determinado de números de tarjetas de crédito. Además, puedes usar conjuntos de reglas de inspección para personalizar los detectores de Infotipos integrados y personalizados mediante reglas de contexto. En este ejemplo, puedes usar las reglas de exclusión para hacer lo siguiente:

  • Inspecciona los números de tarjetas de crédito válidos para un conjunto determinado de rangos de tarjetas, por ejemplo, CardType#1 y CardType#2. Puedes hacerlo mediante una combinación de detectores de Infotipos personalizados basados en regex junto con el detector de Infotipos integrado CREDIT_CARD_NUMBER usando la coincidencia inversa:

    Muestra el conjunto de reglas de inspección para lograr una coincidencia inversa.

  • Reduce la cantidad de falsos positivos causados por la superposición de detectores de Infotipos personalizados basados en regex. Puedes hacerlo con el detector de Infotipos integrado CREDIT_CARD_NUMBER usando la coincidencia completa para identificar tarjetas que no pertenecen al conjunto determinado de rangos de tarjetas:

    Muestra el conjunto de reglas de inspección para lograr una coincidencia completa

En las canalizaciones en las que esperas tener resultados densos de Cloud DLP, puedes usar una métrica personalizada Counter para identificar resultados truncados desde la respuesta de contenido de inspección de Cloud DLP. En el siguiente fragmento de código, se ilustra este enfoque:

@ProcessElement
public void processElement(
    @Element KV<String, InspectContentResponse> element, MultiOutputReceiver out) {
  String fileName = element.getKey().split("\\~")[0];
  String timeStamp = Util.getTimeStamp();

  if (element.getValue().getResult().getFindingsTruncated()) {
    numberofTimesFindingsTruncated.inc();
  }

  numberofTimesFindingsTruncated.inc();

Usa la métrica Counter personalizada para ver con qué frecuencia se truncan los resultados y reduce el tamaño del lote de la canalización si es necesario a fin de minimizar el truncamiento.

¿Qué sigue?