Desidentifica datos sensibles en contenidos de texto

Cloud Data Loss Prevention (DLP) puede desidentificar datos sensibles en el contenido de texto, incluido texto almacenado en estructuras de contenedor como tablas. La desidentificación es el proceso de quitar información de identificación de los datos. La API detecta datos sensibles, como información de identificación personal (PII) y, luego, usa una transformación de desidentificación para enmascarar, borrar o, de otro modo, ocultar los datos. Por ejemplo, a continuación se muestran algunas de las técnicas de desidentificación:

  • “Enmascaramiento” de datos sensibles mediante el reemplazo parcial o completo de caracteres con un símbolo, como un asterisco (*) o un hash (#).
  • Reemplazo de cada instancia de datos sensibles con una string de “token” o sustituta.
  • Encriptación y reemplazo de datos sensibles con una clave predeterminada o generada de manera aleatoria.

Puedes transmitirle información a la API mediante JSON a través de HTTP, así como la CLI y varios lenguajes de programación con las bibliotecas cliente de DLP. Para configurar la CLI, consulta el inicio rápido. Para obtener más información sobre el envío de información en formato JSON, consulta el inicio rápido de JSON.

Descripción general de la API

Para desidentificar datos sensibles, usa el método content.deidentify de Cloud DLP.

A continuación, se muestran las tres partes de desidentificación a una llamada a la API:

  • Los datos a inspeccionar: una string o estructura de tabla (objeto ContentItem) para que la API inspeccione.
  • Para qué inspeccionar: información de configuración de detección (InspectConfig) como qué tipos de datos (o infotipo) buscar, si filtrar resultados que están por encima de un cierto umbral de probabilidad, si mostrar más de un cierto número de resultados y así sucesivamente. No especificar al menos un infotipo en un argumento InspectConfig equivale a especificar todos los infotipos integrados. No se recomienda hacer eso, debido a que puede causar una disminución en el rendimiento y un incremento en el costo.
  • Qué hacer con los resultados de la inspección: la información de configuración (DeidentifyConfig) que define cómo deseas que se desidentifiquen los datos sensibles. En la siguiente sección, encontrarás más detalles sobre este argumento.

La API muestra los mismos elementos que le proporcionaste, en el mismo formato, pero se desidentificó cualquier texto identificado que contiene información sensible de acuerdo con tus criterios.

Transformaciones

Debes especificar una o más transformaciones cuando estableces la configuración de desidentificación (DeidentifyConfig). Existen dos categorías de transformaciones que se muestran a continuación:

  • InfoTypeTransformations: las transformaciones que solo se aplican a valores dentro de texto enviado que se identifican como un infotipo específico.
  • RecordTransformations: las transformaciones que solo se aplican a valores dentro de datos de texto tabulares enviados que se identifican como un infotipo específico o en una columna completa de datos tabulares.

Transformaciones de infotipo

Puedes especificar una o más transformaciones de infotipos por solicitud. Dentro de cada objeto InfoTypeTransformation, especifica ambos de los siguientes:

  • Uno o más infotipos a los que se le debe aplicar una transformación (el objeto de arreglo infoTypes[]).
  • Una transformación primitiva (el objeto PrimitiveTransformation).

Ten en cuenta que la identificación de un infotipo es opcional, pero no identificar al menos un infotipo en un argumento InspectConfig genera que la transformación aplique a todos los infotipos integrados que no tengan una transformación proporcionada. No se recomienda hacer eso, debido a que puede causar una disminución en el rendimiento y un incremento en el costo.

Transformaciones primitivas

Debes especificar al menos una transformación primitiva para aplicar a una entrada, sin importar si se aplica solo a ciertos infotipos o a la string de texto completa. Tienes varias opciones de transformación que puedes ver en la siguiente tabla. Haz clic en el nombre del objeto para obtener más información.

La lista completa de las transformaciones posibles.

replaceConfig

La configuración de replaceConfig en un objeto ReplaceValueConfig reemplaza los valores de entrada coincidentes con un valor que tú especifiques.

Por ejemplo, supón que configuraste replaceConfig en “[email-address]” para todos los infotipos EMAIL_ADDRESS y la siguiente string se envía al Cloud DLP:

My name is Alicia Abernathy, and my email address is aabernathy@example.com.

La string obtenida será la que se muestra a continuación:

My name is Alicia Abernathy, and my email address is [email-address].

En el siguiente ejemplo de JSON, se muestra cómo formar una solicitud de API y lo que muestra la API de Cloud DLP:

Entrada de JSON:

POST https://dlp.googleapis.com/v2/projects/[PROJECT_ID]/content:deidentify?key={YOUR_API_KEY}

{
  "item":{
    "value":"My name is Alicia Abernathy, and my email address is aabernathy@example.com."
  },
  "deidentifyConfig":{
    "infoTypeTransformations":{
      "transformations":[
        {
          "infoTypes":[
            {
              "name":"EMAIL_ADDRESS"
            }
          ],
          "primitiveTransformation":{
            "replaceConfig":{
              "newValue":{
                "stringValue":"[email-address]"
              }
            }
          }
        }
      ]
    }
  },
  "inspectConfig":{
    "infoTypes":[
      {
        "name":"EMAIL_ADDRESS"
      }
    ]
  }
}

Resultado de JSON:

{
  "item":{
    "value":"My name is Alicia Abernathy, and my email address is [email-address]."
  },
  "overview":{
    "transformedBytes":"22",
    "transformationSummaries":[
      {
        "infoType":{
          "name":"EMAIL_ADDRESS"
        },
        "transformation":{
          "replaceConfig":{
            "newValue":{
              "stringValue":"[email-address]"
            }
          }
        },
        "results":[
          {
            "count":"1",
            "code":"SUCCESS"
          }
        ],
        "transformedBytes":"22"
      }
    ]
  }
}
redactConfig

Si especificas redactConfig, se oculta un valor y se quita por completo. El mensaje redactConfig no tiene argumentos; si los especificas, habilitas su transformación.

Por ejemplo, supón que especificaste redactConfig para todos los infotipos EMAIL_ADDRESS y la siguiente string se envía al Cloud DLP:

My name is Alicia Abernathy, and my email address is aabernathy@example.com.

La string obtenida será la que se muestra a continuación:

My name is Alicia Abernathy, and my email address is .

En el siguiente ejemplo de JSON, se muestra cómo formar una solicitud de API y lo que muestra la API de Cloud DLP:

Entrada de JSON:

POST https://dlp.googleapis.com/v2/projects/[PROJECT_ID]/content:deidentify?key={YOUR_API_KEY}

{
  "item":{
    "value":"My name is Alicia Abernathy, and my email address is aabernathy@example.com."
  },
  "deidentifyConfig":{
    "infoTypeTransformations":{
      "transformations":[
        {
          "infoTypes":[
            {
              "name":"EMAIL_ADDRESS"
            }
          ],
          "primitiveTransformation":{
            "redactConfig":{

            }
          }
        }
      ]
    }
  },
  "inspectConfig":{
    "infoTypes":[
      {
        "name":"EMAIL_ADDRESS"
      }
    ]
  }
}

Resultado de JSON:

{
  "item":{
    "value":"My name is Alicia Abernathy, and my email address is ."
  },
  "overview":{
    "transformedBytes":"22",
    "transformationSummaries":[
      {
        "infoType":{
          "name":"EMAIL_ADDRESS"
        },
        "transformation":{
          "redactConfig":{

          }
        },
        "results":[
          {
            "count":"1",
            "code":"SUCCESS"
          }
        ],
        "transformedBytes":"22"
      }
    ]
  }
}
characterMaskConfig

Si configuras characterMaskConfig en un objeto CharacterMaskConfig, se enmascara de manera parcial una string mediante el reemplazo de un número dado de caracteres con un carácter fijo. El enmascaramiento puede comenzar desde el principio o el final de la string. Esta transformación también funciona con los tipos de número como los números enteros largos.

El objeto CharacterMaskConfig tiene varios de sus propios argumentos como los siguientes:

  • maskingCharacter: el carácter que se debe usar para enmascarar cada carácter de un valor sensible. Por ejemplo, puedes especificar un asterisco (*) o un hash (#) para enmascarar una serie de números como los de un número de tarjeta de crédito.
  • numberToMask: el número de caracteres para enmascarar. Si no estableces este valor, todos los caracteres coincidentes se enmascararán.
  • reverseOrder: si se deben enmascarar caracteres en orden inverso. Si estableces reverseOrder como verdadero, los caracteres en valores coincidentes se enmascaran desde el final hacia el principio del valor. Si lo estableces en falso, el enmascaramiento comienza al principio del valor.
  • charactersToIgnore[]: uno o más caracteres para omitir cuando se enmascaran los valores. Por ejemplo, especifica aquí un guion para que los guiones permanezcan en su lugar cuando se enmascara un número de teléfono. Puedes también especificar un grupo de caracteres comunes (CharsToIgnore) para que se ignoren cuando se enmascara.

En el siguiente ejemplo de JSON, se muestra cómo formar una solicitud de API y lo que muestra la API de Cloud DLP:

Entrada de JSON:

POST https://dlp.googleapis.com/v2/projects/[PROJECT_ID]/content:deidentify?key={YOUR_API_KEY}

{
  "item":{
    "value":"My name is Alicia Abernathy, and my email address is aabernathy@example.com."
  },
  "deidentifyConfig":{
    "infoTypeTransformations":{
      "transformations":[
        {
          "infoTypes":[
            {
              "name":"EMAIL_ADDRESS"
            }
          ],
          "primitiveTransformation":{
            "characterMaskConfig":{
              "maskingCharacter":"#",
              "reverseOrder":false,
              "charactersToIgnore":[
                {
                  "charactersToSkip":".@"
                }
              ]
            }
          }
        }
      ]
    }
  },
  "inspectConfig":{
    "infoTypes":[
      {
        "name":"EMAIL_ADDRESS"
      }
    ]
  }
}

Resultado de JSON:

{
  "item":{
    "value":"My name is Alicia Abernathy, and my email address is ##########@#######.###."
  },
  "overview":{
    "transformedBytes":"22",
    "transformationSummaries":[
      {
        "infoType":{
          "name":"EMAIL_ADDRESS"
        },
        "transformation":{
          "characterMaskConfig":{
            "maskingCharacter":"#",
            "charactersToIgnore":[
              {
                "charactersToSkip":".@"
              }
            ]
          }
        },
        "results":[
          {
            "count":"1",
            "code":"SUCCESS"
          }
        ],
        "transformedBytes":"22"
      }
    ]
  }
}

En este ejemplo, se muestra lo que le sucede a la siguiente string cuando se envía a Cloud DLP con el conjunto characterMaskConfig:

My name is Alicia Abernathy, and my email address is aabernathy@example.com.

Cloud DLP muestra lo siguiente:

My name is Alicia Abernathy, and my email address is ##########@#######.###.

A continuación, se muestra el código de ejemplo en varios lenguajes que demuestran cómo usar la API de Cloud DLP para desidentificar datos sensibles mediante técnicas de enmascaramiento.

Java

/**
 * Deidentify a string by masking sensitive information with a character using the DLP API.
 *
 * @param string The string to deidentify.
 * @param maskingCharacter (Optional) The character to mask sensitive data with.
 * @param numberToMask (Optional) The number of characters' worth of sensitive data to mask.
 *     Omitting this value or setting it to 0 masks all sensitive chars.
 * @param projectId ID of Google Cloud project to run the API under.
 */
private static void deIdentifyWithMask(
    String string,
    List<InfoType> infoTypes,
    Character maskingCharacter,
    int numberToMask,
    String projectId) {

  // instantiate a client
  try (DlpServiceClient dlpServiceClient = DlpServiceClient.create()) {

    ContentItem contentItem = ContentItem.newBuilder().setValue(string).build();

    CharacterMaskConfig characterMaskConfig =
        CharacterMaskConfig.newBuilder()
            .setMaskingCharacter(maskingCharacter.toString())
            .setNumberToMask(numberToMask)
            .build();

    // Create the deidentification transformation configuration
    PrimitiveTransformation primitiveTransformation =
        PrimitiveTransformation.newBuilder().setCharacterMaskConfig(characterMaskConfig).build();

    InfoTypeTransformation infoTypeTransformationObject =
        InfoTypeTransformation.newBuilder()
            .setPrimitiveTransformation(primitiveTransformation)
            .build();

    InfoTypeTransformations infoTypeTransformationArray =
        InfoTypeTransformations.newBuilder()
            .addTransformations(infoTypeTransformationObject)
            .build();

    InspectConfig inspectConfig =
        InspectConfig.newBuilder()
            .addAllInfoTypes(infoTypes)
            .build();

    DeidentifyConfig deidentifyConfig =
        DeidentifyConfig.newBuilder()
            .setInfoTypeTransformations(infoTypeTransformationArray)
            .build();

    // Create the deidentification request object
    DeidentifyContentRequest request =
        DeidentifyContentRequest.newBuilder()
            .setParent(ProjectName.of(projectId).toString())
            .setInspectConfig(inspectConfig)
            .setDeidentifyConfig(deidentifyConfig)
            .setItem(contentItem)
            .build();

    // Execute the deidentification request
    DeidentifyContentResponse response = dlpServiceClient.deidentifyContent(request);

    // Print the character-masked input value
    // e.g. "My SSN is 123456789" --> "My SSN is *********"
    String result = response.getItem().getValue();
    System.out.println(result);
  } catch (Exception e) {
    System.out.println("Error in deidentifyWithMask: " + e.getMessage());
  }
}

Node.js

// Imports the Google Cloud Data Loss Prevention library
const DLP = require('@google-cloud/dlp');

// Instantiates a client
const dlp = new DLP.DlpServiceClient();

// The project ID to run the API call under
// const callingProjectId = process.env.GCLOUD_PROJECT;

// The string to deidentify
// const string = 'My SSN is 372819127';

// (Optional) The maximum number of sensitive characters to mask in a match
// If omitted from the request or set to 0, the API will mask any matching characters
// const numberToMask = 5;

// (Optional) The character to mask matching sensitive data with
// const maskingCharacter = 'x';

// Construct deidentification request
const item = {value: string};
const request = {
  parent: dlp.projectPath(callingProjectId),
  deidentifyConfig: {
    infoTypeTransformations: {
      transformations: [
        {
          primitiveTransformation: {
            characterMaskConfig: {
              maskingCharacter: maskingCharacter,
              numberToMask: numberToMask,
            },
          },
        },
      ],
    },
  },
  item: item,
};

try {
  // Run deidentification request
  const [response] = await dlp.deidentifyContent(request);
  const deidentifiedItem = response.item;
  console.log(deidentifiedItem.value);
} catch (err) {
  console.log(`Error in deidentifyWithMask: ${err.message || err}`);
}

Python

def deidentify_with_mask(project, string, info_types, masking_character=None,
                         number_to_mask=0):
    """Uses the Data Loss Prevention API to deidentify sensitive data in a
    string by masking it with a character.
    Args:
        project: The Google Cloud project id to use as a parent resource.
        item: The string to deidentify (will be treated as text).
        masking_character: The character to mask matching sensitive data with.
        number_to_mask: The maximum number of sensitive characters to mask in
            a match. If omitted or set to zero, the API will default to no
            maximum.
    Returns:
        None; the response from the API is printed to the terminal.
    """

    # Import the client library
    import google.cloud.dlp

    # Instantiate a client
    dlp = google.cloud.dlp.DlpServiceClient()

    # Convert the project id into a full resource id.
    parent = dlp.project_path(project)

    # Construct inspect configuration dictionary
    inspect_config = {
        'info_types': [{'name': info_type} for info_type in info_types]
    }

    # Construct deidentify configuration dictionary
    deidentify_config = {
        'info_type_transformations': {
            'transformations': [
                {
                    'primitive_transformation': {
                        'character_mask_config': {
                            'masking_character': masking_character,
                            'number_to_mask': number_to_mask
                        }
                    }
                }
            ]
        }
    }

    # Construct item
    item = {'value': string}

    # Call the API
    response = dlp.deidentify_content(
        parent, inspect_config=inspect_config,
        deidentify_config=deidentify_config, item=item)

    # Print out the results.
    print(response.item.value)

Go

// mask deidentifies the input by masking all provided info types with maskingCharacter
// and prints the result to w.
func mask(w io.Writer, client *dlp.Client, project, input string, infoTypes []string, maskingCharacter string, numberToMask int32) {
	// Convert the info type strings to a list of InfoTypes.
	var i []*dlppb.InfoType
	for _, it := range infoTypes {
		i = append(i, &dlppb.InfoType{Name: it})
	}
	// Create a configured request.
	req := &dlppb.DeidentifyContentRequest{
		Parent: "projects/" + project,
		InspectConfig: &dlppb.InspectConfig{
			InfoTypes: i,
		},
		DeidentifyConfig: &dlppb.DeidentifyConfig{
			Transformation: &dlppb.DeidentifyConfig_InfoTypeTransformations{
				InfoTypeTransformations: &dlppb.InfoTypeTransformations{
					Transformations: []*dlppb.InfoTypeTransformations_InfoTypeTransformation{
						{
							InfoTypes: []*dlppb.InfoType{}, // Match all info types.
							PrimitiveTransformation: &dlppb.PrimitiveTransformation{
								Transformation: &dlppb.PrimitiveTransformation_CharacterMaskConfig{
									CharacterMaskConfig: &dlppb.CharacterMaskConfig{
										MaskingCharacter: maskingCharacter,
										NumberToMask:     numberToMask,
									},
								},
							},
						},
					},
				},
			},
		},
		// The item to analyze.
		Item: &dlppb.ContentItem{
			DataItem: &dlppb.ContentItem_Value{
				Value: input,
			},
		},
	}
	// Send the request.
	r, err := client.DeidentifyContent(context.Background(), req)
	if err != nil {
		log.Fatal(err)
	}
	// Print the result.
	fmt.Fprint(w, r.GetItem().GetValue())
}

PHP

use Google\Cloud\Dlp\V2\CharacterMaskConfig;
use Google\Cloud\Dlp\V2\DlpServiceClient;
use Google\Cloud\Dlp\V2\InfoType;
use Google\Cloud\Dlp\V2\PrimitiveTransformation;
use Google\Cloud\Dlp\V2\DeidentifyConfig;
use Google\Cloud\Dlp\V2\InfoTypeTransformations\InfoTypeTransformation;
use Google\Cloud\Dlp\V2\InfoTypeTransformations;
use Google\Cloud\Dlp\V2\ContentItem;

/**
 * Deidentify sensitive data in a string by masking it with a character.
 * @param string $callingProjectId The GCP Project ID to run the API call under
 * @param string $string The string to deidentify
 * @param int $numberToMask (Optional) The maximum number of sensitive characters to mask in a match
 * @param string $maskingCharacter (Optional) The character to mask matching sensitive data with
 */
function deidentify_mask(
  $callingProjectId,
  $string,
  $numberToMask = 0,
  $maskingCharacter = 'x'
) {
    // Instantiate a client.
    $dlp = new DlpServiceClient();

    // The infoTypes of information to mask
    $ssnInfoType = (new InfoType())
        ->setName('US_SOCIAL_SECURITY_NUMBER');
    $infoTypes = [$ssnInfoType];

    // Create the masking configuration object
    $maskConfig = (new CharacterMaskConfig())
        ->setMaskingCharacter($maskingCharacter)
        ->setNumberToMask($numberToMask);

    // Create the information transform configuration objects
    $primitiveTransformation = (new PrimitiveTransformation())
        ->setCharacterMaskConfig($maskConfig);

    $infoTypeTransformation = (new InfoTypeTransformation())
        ->setPrimitiveTransformation($primitiveTransformation)
        ->setInfoTypes($infoTypes);

    $infoTypeTransformations = (new InfoTypeTransformations())
        ->setTransformations([$infoTypeTransformation]);

    // Create the deidentification configuration object
    $deidentifyConfig = (new DeidentifyConfig())
        ->setInfoTypeTransformations($infoTypeTransformations);

    $item = (new ContentItem())
        ->setValue($string);

    $parent = $dlp->projectName($callingProjectId);

    // Run request
    $response = $dlp->deidentifyContent($parent, [
        'deidentifyConfig' => $deidentifyConfig,
        'item' => $item
    ]);

    // Print the results
    $deidentifiedValue = $response->getItem()->getValue();
    print($deidentifiedValue);
}

C#

public static object DeidMask(
    string projectId,
    string dataValue,
    IEnumerable<InfoType> infoTypes,
    string maskingCharacter,
    int numberToMask,
    bool reverseOrder)
{
    var request = new DeidentifyContentRequest
    {
        ParentAsProjectName = new ProjectName(projectId),
        InspectConfig = new InspectConfig
        {
            InfoTypes = { infoTypes }
        },
        DeidentifyConfig = new DeidentifyConfig
        {
            InfoTypeTransformations = new InfoTypeTransformations
            {
                Transformations = {
                    new InfoTypeTransformations.Types.InfoTypeTransformation
                    {
                        PrimitiveTransformation = new PrimitiveTransformation
                        {
                            CharacterMaskConfig = new CharacterMaskConfig
                            {
                                MaskingCharacter = maskingCharacter,
                                NumberToMask = numberToMask,
                                ReverseOrder = reverseOrder
                            }
                        }
                    }
                }
            }
        },
        Item = new ContentItem
        {
            Value = dataValue
        }
    };

    DlpServiceClient dlp = DlpServiceClient.Create();
    var response = dlp.DeidentifyContent(request);

    Console.WriteLine($"Deidentified content: {response.Item.Value}");
    return 0;
}

cryptoHashConfig

Si configuras cryptoHashConfig en un objeto CryptoHashConfig, se realiza una seudonimización en un valor de salida mediante la generación de un valor sustituto con un hash criptográfico.

Este método reemplaza al valor de entrada con un “resumen” o valor de hash encriptado. El resumen se calcula si tomas el hash SHA-256 del valor de entrada. La clave criptográfica que se usa para hacer el hash es un objeto CryptoKey y debes ser de 32 o 64 bytes de tamaño.

El método genera una representación codificada en Base64 de la salida de hash. Por el momento, solo los valores de número entero y string pueden generar un hash.

Por ejemplo, supón que especificaste cryptoHashConfig para todos los infotipos EMAIL_ADDRESS y el objeto CryptoKey consta de una clave generada de manera aleatoria (una TransientCryptoKey). Entonces, se envía la siguiente string a Cloud DLP:

My name is Alicia Abernathy, and my email address is aabernathy@example.com.

La string obtenida generada de manera criptográfica tendrá el siguiente aspecto:

My name is Alicia Abernathy, and my email address is 41D1567F7F99F1DC2A5FAB886DEE5BEE.

Por supuesto, la string hexadecimal se generará de manera criptográfica y será diferente a la que se muestra aquí.

dateShiftConfig

Si configuras dateShiftConfig en un objeto DateShiftConfig, se realiza un cambio de fecha en un valor de entrada de fecha mediante el cambio de fechas por una cantidad de días aleatoria.

Las técnicas de cambio de fechas cambian un conjunto de fechas de forma aleatoria, pero conservan la secuencia y la duración de un período. En general, el cambio de fechas se realiza en el contexto de un individuo o una entidad. Es decir, debes cambiar todas las fechas para un individuo específico con el mismo diferencial de cambio, pero debes usar un diferencial de cambio distinto para cada individuo.

Para obtener más información sobre cambio de fecha, consulta el tema del concepto de cambio de fecha.

A continuación, se muestra el código de ejemplo en varios lenguajes que demuestran cómo usar la API de Cloud DLP para desidentificar datos mediante el cambio de fecha.

Java

/**
 * @param inputCsvPath The path to the CSV file to deidentify
 * @param outputCsvPath (Optional) path to the output CSV file
 * @param dateFields The list of (date) fields in the CSV file to date shift
 * @param lowerBoundDays The maximum number of days to shift a date backward
 * @param upperBoundDays The maximum number of days to shift a date forward
 * @param contextFieldId (Optional) The column to determine date shift, default : a random shift
 *     amount
 * @param wrappedKey (Optional) The encrypted ('wrapped') AES-256 key to use when shifting dates
 * @param keyName (Optional) The name of the Cloud KMS key used to encrypt ('wrap') the AES-256
 *     key
 * @param projectId ID of Google Cloud project to run the API under.
 */
private static void deidentifyWithDateShift(
    Path inputCsvPath,
    Path outputCsvPath,
    String[] dateFields,
    int lowerBoundDays,
    int upperBoundDays,
    String contextFieldId,
    String wrappedKey,
    String keyName,
    String projectId)
    throws Exception {
  // instantiate a client
  try (DlpServiceClient dlpServiceClient = DlpServiceClient.create()) {

    // Set the maximum days to shift a day backward (lowerbound), forward (upperbound)
    DateShiftConfig.Builder dateShiftConfigBuilder =
        DateShiftConfig.newBuilder()
            .setLowerBoundDays(lowerBoundDays)
            .setUpperBoundDays(upperBoundDays);

    // If contextFieldId, keyName or wrappedKey is set: all three arguments must be valid
    if (contextFieldId != null && keyName != null && wrappedKey != null) {
      dateShiftConfigBuilder.setContext(FieldId.newBuilder().setName(contextFieldId).build());
      KmsWrappedCryptoKey kmsWrappedCryptoKey =
          KmsWrappedCryptoKey.newBuilder()
              .setCryptoKeyName(keyName)
              .setWrappedKey(ByteString.copyFrom(BaseEncoding.base64().decode(wrappedKey)))
              .build();
      dateShiftConfigBuilder.setCryptoKey(
          CryptoKey.newBuilder().setKmsWrapped(kmsWrappedCryptoKey).build());

    } else if (contextFieldId != null || keyName != null || wrappedKey != null) {
      throw new IllegalArgumentException(
          "You must set either ALL or NONE of {contextFieldId, keyName, wrappedKey}!");
    }

    // Read and parse the CSV file
    BufferedReader br = null;
    String line;
    List<Table.Row> rows = new ArrayList<>();
    List<FieldId> headers;

    br = new BufferedReader(new FileReader(inputCsvPath.toFile()));

    // convert csv header to FieldId
    headers =
        Arrays.stream(br.readLine().split(","))
            .map(header -> FieldId.newBuilder().setName(header).build())
            .collect(Collectors.toList());

    while ((line = br.readLine()) != null) {
      // convert csv rows to Table.Row
      rows.add(convertCsvRowToTableRow(line));
    }
    br.close();

    Table table = Table.newBuilder().addAllHeaders(headers).addAllRows(rows).build();

    List<FieldId> dateFieldIds =
        Arrays.stream(dateFields)
            .map(field -> FieldId.newBuilder().setName(field).build())
            .collect(Collectors.toList());

    DateShiftConfig dateShiftConfig = dateShiftConfigBuilder.build();

    FieldTransformation fieldTransformation =
        FieldTransformation.newBuilder()
            .addAllFields(dateFieldIds)
            .setPrimitiveTransformation(
                PrimitiveTransformation.newBuilder().setDateShiftConfig(dateShiftConfig).build())
            .build();

    DeidentifyConfig deidentifyConfig =
        DeidentifyConfig.newBuilder()
            .setRecordTransformations(
                RecordTransformations.newBuilder()
                    .addFieldTransformations(fieldTransformation)
                    .build())
            .build();

    ContentItem tableItem = ContentItem.newBuilder().setTable(table).build();

    DeidentifyContentRequest request =
        DeidentifyContentRequest.newBuilder()
            .setParent(ProjectName.of(projectId).toString())
            .setDeidentifyConfig(deidentifyConfig)
            .setItem(tableItem)
            .build();

    // Execute the deidentification request
    DeidentifyContentResponse response = dlpServiceClient.deidentifyContent(request);

    // Write out the response as a CSV file
    List<FieldId> outputHeaderFields = response.getItem().getTable().getHeadersList();
    List<Table.Row> outputRows = response.getItem().getTable().getRowsList();

    List<String> outputHeaders =
        outputHeaderFields.stream().map(FieldId::getName).collect(Collectors.toList());

    File outputFile = outputCsvPath.toFile();
    if (!outputFile.exists()) {
      outputFile.createNewFile();
    }
    BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(outputFile));

    // write out headers
    bufferedWriter.append(String.join(",", outputHeaders) + "\n");

    // write out each row
    for (Table.Row outputRow : outputRows) {
      String row =
          outputRow
              .getValuesList()
              .stream()
              .map(value -> value.getStringValue())
              .collect(Collectors.joining(","));
      bufferedWriter.append(row + "\n");
    }

    bufferedWriter.flush();
    bufferedWriter.close();

    System.out.println("Successfully saved date-shift output to: " + outputCsvPath.getFileName());
  } catch (Exception e) {
    System.out.println("Error in deidentifyWithDateShift: " + e.getMessage());
  }
}

// Parse string to valid date, return null when invalid
private static LocalDate getValidDate(String dateString) {
  try {
    return LocalDate.parse(dateString);
  } catch (DateTimeParseException e) {
    return null;
  }
}

// convert CSV row into Table.Row
private static Table.Row convertCsvRowToTableRow(String row) {
  String[] values = row.split(",");
  Table.Row.Builder tableRowBuilder = Table.Row.newBuilder();
  for (String value : values) {
    LocalDate date = getValidDate(value);
    if (date != null) {
      // convert to com.google.type.Date
      Date dateValue =
          Date.newBuilder()
              .setYear(date.getYear())
              .setMonth(date.getMonthValue())
              .setDay(date.getDayOfMonth())
              .build();
      Value tableValue = Value.newBuilder().setDateValue(dateValue).build();
      tableRowBuilder.addValues(tableValue);
    } else {
      tableRowBuilder.addValues(Value.newBuilder().setStringValue(value).build());
    }
  }
  return tableRowBuilder.build();
}

Node.js

// Imports the Google Cloud Data Loss Prevention library
const DLP = require('@google-cloud/dlp');

// Instantiates a client
const dlp = new DLP.DlpServiceClient();

// Import other required libraries
const fs = require('fs');

// The project ID to run the API call under
// const callingProjectId = process.env.GCLOUD_PROJECT;

// The path to the CSV file to deidentify
// The first row of the file must specify column names, and all other rows
// must contain valid values
// const inputCsvFile = '/path/to/input/file.csv';

// The path to save the date-shifted CSV file to
// const outputCsvFile = '/path/to/output/file.csv';

// The list of (date) fields in the CSV file to date shift
// const dateFields = [{ name: 'birth_date'}, { name: 'register_date' }];

// The maximum number of days to shift a date backward
// const lowerBoundDays = 1;

// The maximum number of days to shift a date forward
// const upperBoundDays = 1;

// (Optional) The column to determine date shift amount based on
// If this is not specified, a random shift amount will be used for every row
// If this is specified, then 'wrappedKey' and 'keyName' must also be set
// const contextFieldId = [{ name: 'user_id' }];

// (Optional) The name of the Cloud KMS key used to encrypt ('wrap') the AES-256 key
// If this is specified, then 'wrappedKey' and 'contextFieldId' must also be set
// const keyName = 'projects/YOUR_GCLOUD_PROJECT/locations/YOUR_LOCATION/keyRings/YOUR_KEYRING_NAME/cryptoKeys/YOUR_KEY_NAME';

// (Optional) The encrypted ('wrapped') AES-256 key to use when shifting dates
// This key should be encrypted using the Cloud KMS key specified above
// If this is specified, then 'keyName' and 'contextFieldId' must also be set
// const wrappedKey = 'YOUR_ENCRYPTED_AES_256_KEY'

// Helper function for converting CSV rows to Protobuf types
const rowToProto = row => {
  const values = row.split(',');
  const convertedValues = values.map(value => {
    if (Date.parse(value)) {
      const date = new Date(value);
      return {
        dateValue: {
          year: date.getFullYear(),
          month: date.getMonth() + 1,
          day: date.getDate(),
        },
      };
    } else {
      // Convert all non-date values to strings
      return {stringValue: value.toString()};
    }
  });
  return {values: convertedValues};
};

// Read and parse a CSV file
const csvLines = fs
  .readFileSync(inputCsvFile)
  .toString()
  .split('\n')
  .filter(line => line.includes(','));
const csvHeaders = csvLines[0].split(',');
const csvRows = csvLines.slice(1);

// Construct the table object
const tableItem = {
  table: {
    headers: csvHeaders.map(header => {
      return {name: header};
    }),
    rows: csvRows.map(row => rowToProto(row)),
  },
};

// Construct DateShiftConfig
const dateShiftConfig = {
  lowerBoundDays: lowerBoundDays,
  upperBoundDays: upperBoundDays,
};

if (contextFieldId && keyName && wrappedKey) {
  dateShiftConfig.context = {name: contextFieldId};
  dateShiftConfig.cryptoKey = {
    kmsWrapped: {
      wrappedKey: wrappedKey,
      cryptoKeyName: keyName,
    },
  };
} else if (contextFieldId || keyName || wrappedKey) {
  throw new Error(
    'You must set either ALL or NONE of {contextFieldId, keyName, wrappedKey}!'
  );
}

// Construct deidentification request
const request = {
  parent: dlp.projectPath(callingProjectId),
  deidentifyConfig: {
    recordTransformations: {
      fieldTransformations: [
        {
          fields: dateFields,
          primitiveTransformation: {
            dateShiftConfig: dateShiftConfig,
          },
        },
      ],
    },
  },
  item: tableItem,
};

try {
  // Run deidentification request
  const [response] = await dlp.deidentifyContent(request);
  const tableRows = response.item.table.rows;

  // Write results to a CSV file
  tableRows.forEach((row, rowIndex) => {
    const rowValues = row.values.map(
      value =>
        value.stringValue ||
        `${value.dateValue.month}/${value.dateValue.day}/${
          value.dateValue.year
        }`
    );
    csvLines[rowIndex + 1] = rowValues.join(',');
  });
  csvLines.push('');
  fs.writeFileSync(outputCsvFile, csvLines.join('\n'));

  // Print status
  console.log(`Successfully saved date-shift output to ${outputCsvFile}`);
} catch (err) {
  console.log(`Error in deidentifyWithDateShift: ${err.message || err}`);
}

Python

def deidentify_with_date_shift(project, input_csv_file=None,
                               output_csv_file=None, date_fields=None,
                               lower_bound_days=None, upper_bound_days=None,
                               context_field_id=None, wrapped_key=None,
                               key_name=None):
    """Uses the Data Loss Prevention API to deidentify dates in a CSV file by
        pseudorandomly shifting them.
    Args:
        project: The Google Cloud project id to use as a parent resource.
        input_csv_file: The path to the CSV file to deidentify. The first row
            of the file must specify column names, and all other rows must
            contain valid values.
        output_csv_file: The path to save the date-shifted CSV file.
        date_fields: The list of (date) fields in the CSV file to date shift.
            Example: ['birth_date', 'register_date']
        lower_bound_days: The maximum number of days to shift a date backward
        upper_bound_days: The maximum number of days to shift a date forward
        context_field_id: (Optional) The column to determine date shift amount
            based on. If this is not specified, a random shift amount will be
            used for every row. If this is specified, then 'wrappedKey' and
            'keyName' must also be set. Example:
            contextFieldId = [{ 'name': 'user_id' }]
        key_name: (Optional) The name of the Cloud KMS key used to encrypt
            ('wrap') the AES-256 key. Example:
            key_name = 'projects/YOUR_GCLOUD_PROJECT/locations/YOUR_LOCATION/
            keyRings/YOUR_KEYRING_NAME/cryptoKeys/YOUR_KEY_NAME'
        wrapped_key: (Optional) The encrypted ('wrapped') AES-256 key to use.
            This key should be encrypted using the Cloud KMS key specified by
            key_name.
    Returns:
        None; the response from the API is printed to the terminal.
    """
    # Import the client library
    import google.cloud.dlp

    # Instantiate a client
    dlp = google.cloud.dlp.DlpServiceClient()

    # Convert the project id into a full resource id.
    parent = dlp.project_path(project)

    # Convert date field list to Protobuf type
    def map_fields(field):
        return {'name': field}

    if date_fields:
        date_fields = map(map_fields, date_fields)
    else:
        date_fields = []

    # Read and parse the CSV file
    import csv
    from datetime import datetime
    f = []
    with open(input_csv_file, 'r') as csvfile:
        reader = csv.reader(csvfile)
        for row in reader:
            f.append(row)

    #  Helper function for converting CSV rows to Protobuf types
    def map_headers(header):
        return {'name': header}

    def map_data(value):
        try:
            date = datetime.strptime(value, '%m/%d/%Y')
            return {
                'date_value': {
                    'year': date.year,
                    'month': date.month,
                    'day': date.day
                }
            }
        except ValueError:
            return {'string_value': value}

    def map_rows(row):
        return {'values': map(map_data, row)}

    # Using the helper functions, convert CSV rows to protobuf-compatible
    # dictionaries.
    csv_headers = map(map_headers, f[0])
    csv_rows = map(map_rows, f[1:])

    # Construct the table dict
    table_item = {
        'table': {
            'headers': csv_headers,
            'rows': csv_rows
        }
    }

    # Construct date shift config
    date_shift_config = {
        'lower_bound_days': lower_bound_days,
        'upper_bound_days': upper_bound_days
    }

    # If using a Cloud KMS key, add it to the date_shift_config.
    # The wrapped key is base64-encoded, but the library expects a binary
    # string, so decode it here.
    if context_field_id and key_name and wrapped_key:
        import base64
        date_shift_config['context'] = {'name': context_field_id}
        date_shift_config['crypto_key'] = {
            'kms_wrapped': {
                'wrapped_key': base64.b64decode(wrapped_key),
                'crypto_key_name': key_name
            }
        }
    elif context_field_id or key_name or wrapped_key:
        raise ValueError("""You must set either ALL or NONE of
        [context_field_id, key_name, wrapped_key]!""")

    # Construct Deidentify Config
    deidentify_config = {
        'record_transformations': {
            'field_transformations': [
                {
                    'fields': date_fields,
                    'primitive_transformation': {
                        'date_shift_config': date_shift_config
                    }
                }
            ]
        }
    }

    # Write to CSV helper methods
    def write_header(header):
        return header.name

    def write_data(data):
        return data.string_value or '%s/%s/%s' % (data.date_value.month,
                                                  data.date_value.day,
                                                  data.date_value.year)

    # Call the API
    response = dlp.deidentify_content(
        parent, deidentify_config=deidentify_config, item=table_item)

    # Write results to CSV file
    with open(output_csv_file, 'w') as csvfile:
        write_file = csv.writer(csvfile, delimiter=',')
        write_file.writerow(map(write_header, response.item.table.headers))
        for row in response.item.table.rows:
            write_file.writerow(map(write_data, row.values))
    # Print status
    print('Successfully saved date-shift output to {}'.format(
                output_csv_file))

Go

// deidentifyDateShift shifts dates found in the input between lowerBoundDays and
// upperBoundDays.
func deidentifyDateShift(w io.Writer, client *dlp.Client, project string, lowerBoundDays, upperBoundDays int32, input string) {
	// Create a configured request.
	req := &dlppb.DeidentifyContentRequest{
		Parent: "projects/" + project,
		DeidentifyConfig: &dlppb.DeidentifyConfig{
			Transformation: &dlppb.DeidentifyConfig_InfoTypeTransformations{
				InfoTypeTransformations: &dlppb.InfoTypeTransformations{
					Transformations: []*dlppb.InfoTypeTransformations_InfoTypeTransformation{
						{
							InfoTypes: []*dlppb.InfoType{}, // Match all info types.
							PrimitiveTransformation: &dlppb.PrimitiveTransformation{
								Transformation: &dlppb.PrimitiveTransformation_DateShiftConfig{
									DateShiftConfig: &dlppb.DateShiftConfig{
										LowerBoundDays: lowerBoundDays,
										UpperBoundDays: upperBoundDays,
									},
								},
							},
						},
					},
				},
			},
		},
		// The InspectConfig is used to identify the DATE fields.
		InspectConfig: &dlppb.InspectConfig{
			InfoTypes: []*dlppb.InfoType{
				{
					Name: "DATE",
				},
			},
		},
		// The item to analyze.
		Item: &dlppb.ContentItem{
			DataItem: &dlppb.ContentItem_Value{
				Value: input,
			},
		},
	}
	// Send the request.
	r, err := client.DeidentifyContent(context.Background(), req)
	if err != nil {
		log.Fatal(err)
	}
	// Print the result.
	fmt.Fprint(w, r.GetItem().GetValue())
}

PHP

use Google\Cloud\Dlp\V2\ContentItem;
use Google\Cloud\Dlp\V2\CryptoKey;
use Google\Cloud\Dlp\V2\DateShiftConfig;
use Google\Cloud\Dlp\V2\DeidentifyConfig;
use Google\Cloud\Dlp\V2\DlpServiceClient;
use Google\Cloud\Dlp\V2\FieldId;
use Google\Cloud\Dlp\V2\FieldTransformation;
use Google\Cloud\Dlp\V2\KmsWrappedCryptoKey;
use Google\Cloud\Dlp\V2\PrimitiveTransformation;
use Google\Cloud\Dlp\V2\RecordTransformations;
use Google\Cloud\Dlp\V2\Table;
use Google\Cloud\Dlp\V2\Table\Row;
use Google\Cloud\Dlp\V2\Value;
use Google\Type\Date;
use DateTime;

/**
 * Deidentify dates in a CSV file by pseudorandomly shifting them.
 *
 * @param string $callingProject The GCP Project ID to run the API call under
 * @param string $inputCsvFile The path to the CSV file to deidentify
 * @param string $outputCsvFile The path to save the date-shifted CSV file to
 * @param array $dateFieldNames The list of (date) fields in the CSV file to date shift
 * @param string $lowerBoundDays The maximum number of days to shift a date backward
 * @param string $upperBoundDays The maximum number of days to shift a date forward
 * @param string contextFieldName (Optional) The column to determine date shift amount based on
 *        If this is not specified, a random shift amount will be used for every row.
 *        If this is specified, then 'wrappedKey' and 'keyName' must also be set
 * @param string keyName (Optional) The encrypted ('wrapped') AES-256 key to use when shifting dates
 *        If this is specified, then 'wrappedKey' and 'contextFieldName' must also be set
 * @param string wrappedKey (Optional) The name of the Cloud KMS key used to encrypt ('wrap') the AES-256 key
 *        If this is specified, then 'keyName' and 'contextFieldName' must also be set
 */
function deidentify_dates(
    $callingProjectId,
    $inputCsvFile,
    $outputCsvFile,
    $dateFieldNames,
    $lowerBoundDays,
    $upperBoundDays,
    $contextFieldName = '',
    $keyName = '',
    $wrappedKey = ''
) {
    // Instantiate a client.
    $dlp = new DlpServiceClient();

    // Read a CSV file
    $csvLines = file($inputCsvFile, FILE_IGNORE_NEW_LINES);
    $csvHeaders = explode(',', $csvLines[0]);
    $csvRows = array_slice($csvLines, 1);

    // Convert CSV file into protobuf objects
    $tableHeaders = array_map(function ($csvHeader) {
        return (new FieldId)->setName($csvHeader);
    }, $csvHeaders);

    $tableRows = array_map(function ($csvRow) {
        $rowValues = array_map(function ($csvValue) {
            if ($csvDate = DateTime::createFromFormat('m/d/Y', $csvValue)) {
                $date = (new Date())
                    ->setYear((int) $csvDate->format('Y'))
                    ->setMonth((int) $csvDate->format('m'))
                    ->setDay((int) $csvDate->format('d'));
                return (new Value())
                    ->setDateValue($date);
            } else {
                return (new Value())
                    ->setStringValue($csvValue);
            }
        }, explode(',', $csvRow));

        return (new Row())
            ->setValues($rowValues);
    }, $csvRows);

    // Convert date fields into protobuf objects
    $dateFields = array_map(function ($dateFieldName) {
        return (new FieldId())->setName($dateFieldName);
    }, $dateFieldNames);

    // Construct the table object
    $table = (new Table())
        ->setHeaders($tableHeaders)
        ->setRows($tableRows);

    $item = (new ContentItem())
        ->setTable($table);

    // Construct dateShiftConfig
    $dateShiftConfig = (new DateShiftConfig())
        ->setLowerBoundDays($lowerBoundDays)
        ->setUpperBoundDays($upperBoundDays);

    if ($contextFieldName && $keyName && $wrappedKey) {
        $contextField = (new FieldId())
            ->setName($contextFieldName);

        // Create the wrapped crypto key configuration object
        $kmsWrappedCryptoKey = (new KmsWrappedCryptoKey())
            ->setWrappedKey(base64_decode($wrappedKey))
            ->setCryptoKeyName($keyName);

        $cryptoKey = (new CryptoKey())
            ->setKmsWrapped($kmsWrappedCryptoKey);

        $dateShiftConfig
            ->setContext($contextField)
            ->setCryptoKey($cryptoKey);
    } elseif ($contextFieldName || $keyName || $wrappedKey) {
        throw new Exception('You must set either ALL or NONE of {$contextFieldName, $keyName, $wrappedKey}!');
    }

    // Create the information transform configuration objects
    $primitiveTransformation = (new PrimitiveTransformation())
        ->setDateShiftConfig($dateShiftConfig);

    $fieldTransformation = (new FieldTransformation())
        ->setPrimitiveTransformation($primitiveTransformation)
        ->setFields($dateFields);

    $recordTransformations = (new RecordTransformations())
        ->setFieldTransformations([$fieldTransformation]);

    // Create the deidentification configuration object
    $deidentifyConfig = (new DeidentifyConfig())
        ->setRecordTransformations($recordTransformations);

    $parent = $dlp->projectName($callingProjectId);

    // Run request
    $response = $dlp->deidentifyContent($parent, [
        'deidentifyConfig' => $deidentifyConfig,
        'item' => $item
    ]);

    // Check for errors
    foreach ($response->getOverview()->getTransformationSummaries() as $summary) {
        foreach ($summary->getResults() as $result) {
            if ($details = $result->getDetails()) {
                printf('Error: %s' . PHP_EOL, $details);
                return;
            }
        }
    }

    // Save the results to a file
    $csvRef = fopen($outputCsvFile, 'w');
    fputcsv($csvRef, $csvHeaders);
    foreach ($response->getItem()->getTable()->getRows() as $tableRow) {
        $values = array_map(function ($tableValue) {
            if ($tableValue->getStringValue()) {
                return $tableValue->getStringValue();
            }
            $protoDate = $tableValue->getDateValue();
            $date = mktime(0, 0, 0, $protoDate->getMonth(), $protoDate->getDay(), $protoDate->getYear());
            return strftime('%D', $date);
        }, iterator_to_array($tableRow->getValues()));
        fputcsv($csvRef, $values);
    };
    fclose($csvRef);
    printf('Deidentified dates written to %s' . PHP_EOL, $outputCsvFile);
}

C#

public static object DeidDateShift(
    string projectId,
    string inputCsvFile,
    string outputCsvFile,
    int lowerBoundDays,
    int upperBoundDays,
    string dateFields,
    string contextField = "",
    string keyName = "",
    string wrappedKey = "")
{
    var dlp = DlpServiceClient.Create();

    // Read file
    string[] csvLines = File.ReadAllLines(inputCsvFile);
    string[] csvHeaders = csvLines[0].Split(',');
    string[] csvRows = csvLines.Skip(1).ToArray();

    // Convert dates to protobuf format, and everything else to a string
    var protoHeaders = csvHeaders.Select(header => new FieldId { Name = header });
    var protoRows = csvRows.Select(CsvRow =>
    {
        var rowValues = CsvRow.Split(',');
        var protoValues = rowValues.Select(RowValue =>
        {
            System.DateTime parsedDate;
            if (System.DateTime.TryParse(RowValue, out parsedDate))
            {
                return new Value
                {
                    DateValue = new Google.Type.Date
                    {
                        Year = parsedDate.Year,
                        Month = parsedDate.Month,
                        Day = parsedDate.Day
                    }
                };
            }
            else
            {
                return new Value
                {
                    StringValue = RowValue
                };
            }
        });

        var rowObject = new Table.Types.Row();
        rowObject.Values.Add(protoValues);
        return rowObject;
    });

    var dateFieldList = dateFields
        .Split(',')
        .Select(field => new FieldId { Name = field });

    // Construct + execute the request
    var dateShiftConfig = new DateShiftConfig
    {
        LowerBoundDays = lowerBoundDays,
        UpperBoundDays = upperBoundDays
    };
    bool hasKeyName = !String.IsNullOrEmpty(keyName);
    bool hasWrappedKey = !String.IsNullOrEmpty(wrappedKey);
    bool hasContext = !String.IsNullOrEmpty(contextField);
    if (hasKeyName && hasWrappedKey && hasContext)
    {
        dateShiftConfig.Context = new FieldId { Name = contextField };
        dateShiftConfig.CryptoKey = new CryptoKey
        {
            KmsWrapped = new KmsWrappedCryptoKey
            {
                WrappedKey = ByteString.FromBase64(wrappedKey),
                CryptoKeyName = keyName
            }
        };
    }
    else if (hasKeyName || hasWrappedKey || hasContext)
    {
        throw new ArgumentException("Must specify ALL or NONE of: {contextFieldId, keyName, wrappedKey}!");
    }

    var deidConfig = new DeidentifyConfig
    {
        RecordTransformations = new RecordTransformations
        {
            FieldTransformations =
            {
                new FieldTransformation
                {
                    PrimitiveTransformation = new PrimitiveTransformation
                    {
                        DateShiftConfig = dateShiftConfig
                    },
                    Fields = { dateFieldList }
                }
            }
        }
    };

    DeidentifyContentResponse response = dlp.DeidentifyContent(
        new DeidentifyContentRequest
        {
            Parent = $"projects/{projectId}",
            DeidentifyConfig = deidConfig,
            Item = new ContentItem
            {
                Table = new Table
                {
                    Headers = { protoHeaders },
                    Rows = { protoRows }
                }
            }
        });

    // Save the results
    List<String> outputLines = new List<string>();
    outputLines.Add(csvLines[0]);

    outputLines.AddRange(response.Item.Table.Rows.Select(ProtoRow =>
    {
        var Values = ProtoRow.Values.Select(ProtoValue =>
        {
            if (ProtoValue.DateValue != null)
            {
                var ProtoDate = ProtoValue.DateValue;
                System.DateTime Date = new System.DateTime(
                    ProtoDate.Year, ProtoDate.Month, ProtoDate.Day);
                return Date.ToShortDateString();
            }
            else
            {
                return ProtoValue.StringValue;
            }
        });
        return String.Join(',', Values);
    }));

    File.WriteAllLines(outputCsvFile, outputLines);

    return 0;
}

cryptoReplaceFfxFpeConfig

Si configuras cryptoReplaceFfxFpeConfig en un objeto CryptoReplaceFfxFpeConfig, se realiza una seudonimización en un valor de entrada mediante el reemplazo de un valor de entrada con un token. Este token tiene las siguientes características:

  • Es el valor de entrada encriptado.
  • Tiene la misma longitud que el valor de entrada.
  • Se calcula con la encriptación de preservación de formato (FPE) en el modo FFX asignado en la clave criptográfica especificada por cryptoKey.
  • Está compuesto por los caracteres especificados por alphabet.

El valor de entrada debe cumplir las siguientes condiciones:

  • Debe constar de al menos dos caracteres (o la string vacía).
  • Debe estar compuesto por los caracteres especificados por alphabet, y el alphabet debe estar limitado entre 2 y 64 caracteres.

Cloud DLP calcula el token de reemplazo con una clave criptográfica. Debes proporcionar esta clave de una de las siguientes tres maneras:

  1. Incorpórala sin encriptar en la solicitud de la API.
  2. Solicita que Cloud DLP la genere.
  3. Incorpórala encriptada en la solicitud de la API. Para esta opción, la clave está unida (encriptada) por una clave de Cloud Key Management Service.

Para crear una clave unida de Cloud KMS, envías una solicitud que contiene un valor de campo plaintext de 16, 24, o 32 bytes al método projects.locations.keyRings.cryptoKeys.encrypt de Cloud KMS. La clave unida es el valor en el campo ciphertext de la respuesta del método.

El valor es una string codificada en base64 predeterminada. Para establecer este valor en Cloud DLP, debe estar decodificado en una string de bytes. Los siguientes fragmentos de código resaltan cómo realizar eso en varios lenguajes. A continuación de estos fragmentos, se proporcionan ejemplos de extremo a extremo.

Java

KmsWrappedCryptoKey.newBuilder()
    .setWrappedKey(ByteString.copyFrom(BaseEncoding.base64().decode(wrappedKey)))

Python

# The wrapped key is Base64-encoded, but the library expects a binary
# string, so decode it here.
import base64
wrapped_key = base64.b64decode(wrapped_key)

PHP

// Create the wrapped crypto key configuration object
$kmsWrappedCryptoKey = (new KmsWrappedCryptoKey())
    ->setWrappedKey(base64_decode($wrappedKey))
    ->setCryptoKeyName($keyName);

C#

WrappedKey = ByteString.FromBase64(wrappedKey)

Para obtener más información sobre la encriptación y la desencriptación de datos mediante Cloud KMS, consulta encriptación y desencriptación de datos.

A continuación, se muestra el código de ejemplo en varios lenguajes que demuestran cómo usar Cloud DLP para desidentificar datos sensibles mediante el reemplazo de un valor de entrada con un token.

Java

/**
 * Deidentify a string by encrypting sensitive information while preserving format.
 *
 * @param string The string to deidentify.
 * @param alphabet The set of characters to use when encrypting the input. For more information,
 *     see cloud.google.com/dlp/docs/reference/rest/v2/content/deidentify
 * @param keyName The name of the Cloud KMS key to use when decrypting the wrapped key.
 * @param wrappedKey The encrypted (or "wrapped") AES-256 encryption key.
 * @param projectId ID of Google Cloud project to run the API under.
 */
private static void deIdentifyWithFpe(
    String string,
    List<InfoType> infoTypes,
    FfxCommonNativeAlphabet alphabet,
    String keyName,
    String wrappedKey,
    String projectId,
    String surrogateType) {
  // instantiate a client
  try (DlpServiceClient dlpServiceClient = DlpServiceClient.create()) {
    ContentItem contentItem = ContentItem.newBuilder().setValue(string).build();

    // Create the format-preserving encryption (FPE) configuration
    KmsWrappedCryptoKey kmsWrappedCryptoKey =
        KmsWrappedCryptoKey.newBuilder()
            .setWrappedKey(ByteString.copyFrom(BaseEncoding.base64().decode(wrappedKey)))
            .setCryptoKeyName(keyName)
            .build();

    CryptoKey cryptoKey = CryptoKey.newBuilder().setKmsWrapped(kmsWrappedCryptoKey).build();

    CryptoReplaceFfxFpeConfig cryptoReplaceFfxFpeConfig =
        CryptoReplaceFfxFpeConfig.newBuilder()
            .setCryptoKey(cryptoKey)
            .setCommonAlphabet(alphabet)
            .setSurrogateInfoType(InfoType.newBuilder().setName(surrogateType).build())
            .build();

    // Create the deidentification transformation configuration
    PrimitiveTransformation primitiveTransformation =
        PrimitiveTransformation.newBuilder()
            .setCryptoReplaceFfxFpeConfig(cryptoReplaceFfxFpeConfig)
            .build();

    InfoTypeTransformation infoTypeTransformationObject =
        InfoTypeTransformation.newBuilder()
            .setPrimitiveTransformation(primitiveTransformation)
            .build();

    InfoTypeTransformations infoTypeTransformationArray =
        InfoTypeTransformations.newBuilder()
            .addTransformations(infoTypeTransformationObject)
            .build();

    InspectConfig inspectConfig =
        InspectConfig.newBuilder()
            .addAllInfoTypes(infoTypes)
            .build();

    // Create the deidentification request object
    DeidentifyConfig deidentifyConfig =
        DeidentifyConfig.newBuilder()
            .setInfoTypeTransformations(infoTypeTransformationArray)
            .build();

    DeidentifyContentRequest request =
        DeidentifyContentRequest.newBuilder()
            .setParent(ProjectName.of(projectId).toString())
            .setInspectConfig(inspectConfig)
            .setDeidentifyConfig(deidentifyConfig)
            .setItem(contentItem)
            .build();

    // Execute the deidentification request
    DeidentifyContentResponse response = dlpServiceClient.deidentifyContent(request);

    // Print the deidentified input value
    // e.g. "My SSN is 123456789" --> "My SSN is 7261298621"
    String result = response.getItem().getValue();
    System.out.println(result);
  } catch (Exception e) {
    System.out.println("Error in deidentifyWithFpe: " + e.getMessage());
  }
}

Node.js

// Imports the Google Cloud Data Loss Prevention library
const DLP = require('@google-cloud/dlp');

// Instantiates a client
const dlp = new DLP.DlpServiceClient();

// The project ID to run the API call under
// const callingProjectId = process.env.GCLOUD_PROJECT;

// The string to deidentify
// const string = 'My SSN is 372819127';

// The set of characters to replace sensitive ones with
// For more information, see https://cloud.google.com/dlp/docs/reference/rest/v2/organizations.deidentifyTemplates#ffxcommonnativealphabet
// const alphabet = 'ALPHA_NUMERIC';

// The name of the Cloud KMS key used to encrypt ('wrap') the AES-256 key
// const keyName = 'projects/YOUR_GCLOUD_PROJECT/locations/YOUR_LOCATION/keyRings/YOUR_KEYRING_NAME/cryptoKeys/YOUR_KEY_NAME';

// The encrypted ('wrapped') AES-256 key to use
// This key should be encrypted using the Cloud KMS key specified above
// const wrappedKey = 'YOUR_ENCRYPTED_AES_256_KEY'

// (Optional) The name of the surrogate custom info type to use
// Only necessary if you want to reverse the deidentification process
// Can be essentially any arbitrary string, as long as it doesn't appear
// in your dataset otherwise.
// const surrogateType = 'SOME_INFO_TYPE_DEID';

// Construct FPE config
const cryptoReplaceFfxFpeConfig = {
  cryptoKey: {
    kmsWrapped: {
      wrappedKey: wrappedKey,
      cryptoKeyName: keyName,
    },
  },
  commonAlphabet: alphabet,
};
if (surrogateType) {
  cryptoReplaceFfxFpeConfig.surrogateInfoType = {
    name: surrogateType,
  };
}

// Construct deidentification request
const item = {value: string};
const request = {
  parent: dlp.projectPath(callingProjectId),
  deidentifyConfig: {
    infoTypeTransformations: {
      transformations: [
        {
          primitiveTransformation: {
            cryptoReplaceFfxFpeConfig: cryptoReplaceFfxFpeConfig,
          },
        },
      ],
    },
  },
  item: item,
};

try {
  // Run deidentification request
  const [response] = await dlp.deidentifyContent(request);
  const deidentifiedItem = response.item;
  console.log(deidentifiedItem.value);
} catch (err) {
  console.log(`Error in deidentifyWithFpe: ${err.message || err}`);
}

Python

def deidentify_with_fpe(project, string, info_types, alphabet=None,
                        surrogate_type=None, key_name=None, wrapped_key=None):
    """Uses the Data Loss Prevention API to deidentify sensitive data in a
    string using Format Preserving Encryption (FPE).
    Args:
        project: The Google Cloud project id to use as a parent resource.
        item: The string to deidentify (will be treated as text).
        alphabet: The set of characters to replace sensitive ones with. For
            more information, see https://cloud.google.com/dlp/docs/reference/
            rest/v2beta2/organizations.deidentifyTemplates#ffxcommonnativealphabet
        surrogate_type: The name of the surrogate custom info type to use. Only
            necessary if you want to reverse the deidentification process. Can
            be essentially any arbitrary string, as long as it doesn't appear
            in your dataset otherwise.
        key_name: The name of the Cloud KMS key used to encrypt ('wrap') the
            AES-256 key. Example:
            key_name = 'projects/YOUR_GCLOUD_PROJECT/locations/YOUR_LOCATION/
            keyRings/YOUR_KEYRING_NAME/cryptoKeys/YOUR_KEY_NAME'
        wrapped_key: The encrypted ('wrapped') AES-256 key to use. This key
            should be encrypted using the Cloud KMS key specified by key_name.
    Returns:
        None; the response from the API is printed to the terminal.
    """
    # Import the client library
    import google.cloud.dlp

    # Instantiate a client
    dlp = google.cloud.dlp.DlpServiceClient()

    # Convert the project id into a full resource id.
    parent = dlp.project_path(project)

    # The wrapped key is base64-encoded, but the library expects a binary
    # string, so decode it here.
    import base64
    wrapped_key = base64.b64decode(wrapped_key)

    # Construct FPE configuration dictionary
    crypto_replace_ffx_fpe_config = {
        'crypto_key': {
            'kms_wrapped': {
                'wrapped_key': wrapped_key,
                'crypto_key_name': key_name
            }
        },
        'common_alphabet': alphabet
    }

    # Add surrogate type
    if surrogate_type:
        crypto_replace_ffx_fpe_config['surrogate_info_type'] = {
            'name': surrogate_type
        }

    # Construct inspect configuration dictionary
    inspect_config = {
        'info_types': [{'name': info_type} for info_type in info_types]
    }

    # Construct deidentify configuration dictionary
    deidentify_config = {
        'info_type_transformations': {
            'transformations': [
                {
                    'primitive_transformation': {
                        'crypto_replace_ffx_fpe_config':
                            crypto_replace_ffx_fpe_config
                    }
                }
            ]
        }
    }

    # Convert string to item
    item = {'value': string}

    # Call the API
    response = dlp.deidentify_content(
        parent, inspect_config=inspect_config,
        deidentify_config=deidentify_config, item=item)

    # Print results
    print(response.item.value)

Go

// deidentifyFPE deidentifies the input with FPE (Format Preserving Encryption).
// keyFileName is the file name with the KMS wrapped key and cryptoKeyName is the
// full KMS key resource name used to wrap the key. surrogateInfoType is an
// optional identifier needed for reidentification. surrogateInfoType can be any
// value not found in your input.
func deidentifyFPE(w io.Writer, client *dlp.Client, project, input string, infoTypes []string, keyFileName, cryptoKeyName, surrogateInfoType string) {
	// Convert the info type strings to a list of InfoTypes.
	var i []*dlppb.InfoType
	for _, it := range infoTypes {
		i = append(i, &dlppb.InfoType{Name: it})
	}
	// Read the key file.
	keyBytes, err := ioutil.ReadFile(keyFileName)
	if err != nil {
		log.Fatalf("error reading file: %v", err)
	}
	// Create a configured request.
	req := &dlppb.DeidentifyContentRequest{
		Parent: "projects/" + project,
		InspectConfig: &dlppb.InspectConfig{
			InfoTypes: i,
		},
		DeidentifyConfig: &dlppb.DeidentifyConfig{
			Transformation: &dlppb.DeidentifyConfig_InfoTypeTransformations{
				InfoTypeTransformations: &dlppb.InfoTypeTransformations{
					Transformations: []*dlppb.InfoTypeTransformations_InfoTypeTransformation{
						{
							InfoTypes: []*dlppb.InfoType{}, // Match all info types.
							PrimitiveTransformation: &dlppb.PrimitiveTransformation{
								Transformation: &dlppb.PrimitiveTransformation_CryptoReplaceFfxFpeConfig{
									CryptoReplaceFfxFpeConfig: &dlppb.CryptoReplaceFfxFpeConfig{
										CryptoKey: &dlppb.CryptoKey{
											Source: &dlppb.CryptoKey_KmsWrapped{
												KmsWrapped: &dlppb.KmsWrappedCryptoKey{
													WrappedKey:    keyBytes,
													CryptoKeyName: cryptoKeyName,
												},
											},
										},
										// Set the alphabet used for the output.
										Alphabet: &dlppb.CryptoReplaceFfxFpeConfig_CommonAlphabet{
											CommonAlphabet: dlppb.CryptoReplaceFfxFpeConfig_ALPHA_NUMERIC,
										},
										// Set the surrogate info type, used for reidentification.
										SurrogateInfoType: &dlppb.InfoType{
											Name: surrogateInfoType,
										},
									},
								},
							},
						},
					},
				},
			},
		},
		// The item to analyze.
		Item: &dlppb.ContentItem{
			DataItem: &dlppb.ContentItem_Value{
				Value: input,
			},
		},
	}
	// Send the request.
	r, err := client.DeidentifyContent(context.Background(), req)
	if err != nil {
		log.Fatal(err)
	}
	// Print the result.
	fmt.Fprint(w, r.GetItem().GetValue())
}

PHP

use Google\Cloud\Dlp\V2\CryptoReplaceFfxFpeConfig;
use Google\Cloud\Dlp\V2\CryptoReplaceFfxFpeConfig\FfxCommonNativeAlphabet;
use Google\Cloud\Dlp\V2\CryptoKey;
use Google\Cloud\Dlp\V2\DlpServiceClient;
use Google\Cloud\Dlp\V2\PrimitiveTransformation;
use Google\Cloud\Dlp\V2\KmsWrappedCryptoKey;
use Google\Cloud\Dlp\V2\InfoType;
use Google\Cloud\Dlp\V2\DeidentifyConfig;
use Google\Cloud\Dlp\V2\InfoTypeTransformations\InfoTypeTransformation;
use Google\Cloud\Dlp\V2\InfoTypeTransformations;
use Google\Cloud\Dlp\V2\ContentItem;

/**
 * Deidentify a string using Format-Preserving Encryption (FPE).
 *
 * @param string $callingProjectId The GCP Project ID to run the API call under
 * @param string $string The string to deidentify
 * @param string $keyName The name of the Cloud KMS key used to encrypt ('wrap') the AES-256 key
 * @param wrappedKey $wrappedKey The AES-256 key to use, encrypted ('wrapped') with the KMS key
 *        defined by $keyName.
 * @param string $surrogateTypeName Optional surrogate custom info type to enable
 *        reidentification. Can be essentially any arbitrary string that doesn't
 *        appear in your dataset'
 */
function deidentify_fpe(
    $callingProjectId,
    $string,
    $keyName,
    $wrappedKey,
    $surrogateTypeName = ''
) {
    // Instantiate a client.
    $dlp = new DlpServiceClient();

    // The infoTypes of information to mask
    $ssnInfoType = (new InfoType())
        ->setName('US_SOCIAL_SECURITY_NUMBER');
    $infoTypes = [$ssnInfoType];

    // Create the wrapped crypto key configuration object
    $kmsWrappedCryptoKey = (new KmsWrappedCryptoKey())
        ->setWrappedKey(base64_decode($wrappedKey))
        ->setCryptoKeyName($keyName);

    // The set of characters to replace sensitive ones with
    // For more information, see https://cloud.google.com/dlp/docs/reference/rest/V2/organizations.deidentifyTemplates#ffxcommonnativealphabet
    $commonAlphabet = FfxCommonNativeAlphabet::NUMERIC;

    // Create the crypto key configuration object
    $cryptoKey = (new CryptoKey())
        ->setKmsWrapped($kmsWrappedCryptoKey);

    // Create the crypto FFX FPE configuration object
    $cryptoReplaceFfxFpeConfig = (new CryptoReplaceFfxFpeConfig())
        ->setCryptoKey($cryptoKey)
        ->setCommonAlphabet($commonAlphabet);
    if ($surrogateTypeName) {
        $surrogateType = (new InfoType())
            ->setName($surrogateTypeName);
        $cryptoReplaceFfxFpeConfig->setSurrogateInfoType($surrogateType);
    }

    // Create the information transform configuration objects
    $primitiveTransformation = (new PrimitiveTransformation())
        ->setCryptoReplaceFfxFpeConfig($cryptoReplaceFfxFpeConfig);

    $infoTypeTransformation = (new InfoTypeTransformation())
        ->setPrimitiveTransformation($primitiveTransformation)
        ->setInfoTypes($infoTypes);

    $infoTypeTransformations = (new InfoTypeTransformations())
        ->setTransformations([$infoTypeTransformation]);

    // Create the deidentification configuration object
    $deidentifyConfig = (new DeidentifyConfig())
        ->setInfoTypeTransformations($infoTypeTransformations);

    $content = (new ContentItem())
        ->setValue($string);

    $parent = $dlp->projectName($callingProjectId);

    // Run request
    $response = $dlp->deidentifyContent($parent, [
        'deidentifyConfig' => $deidentifyConfig,
        'item' => $content
    ]);

    // Print the results
    $deidentifiedValue = $response->getItem()->getValue();
    print($deidentifiedValue);
}

C#

public static object DeidFpe(
    string projectId,
    string dataValue,
    IEnumerable<InfoType> infoTypes,
    string keyName,
    string wrappedKey,
    string alphabet)
{
    var deidentifyConfig = new DeidentifyConfig
    {
        InfoTypeTransformations = new InfoTypeTransformations
        {
            Transformations =
            {
                new InfoTypeTransformations.Types.InfoTypeTransformation
                {
                    PrimitiveTransformation = new PrimitiveTransformation
                    {
                        CryptoReplaceFfxFpeConfig = new CryptoReplaceFfxFpeConfig
                        {
                            CommonAlphabet = (FfxCommonNativeAlphabet) Enum.Parse(typeof(FfxCommonNativeAlphabet), alphabet),
                            CryptoKey = new CryptoKey
                            {
                                KmsWrapped = new KmsWrappedCryptoKey
                                {
                                    CryptoKeyName = keyName,
                                    WrappedKey = ByteString.FromBase64(wrappedKey)
                                }
                            },
                            SurrogateInfoType = new InfoType
                            {
                                Name = "TOKEN"
                            }
                        }
                    }
                }
            }
        }
    };

    DlpServiceClient dlp = DlpServiceClient.Create();
    var response = dlp.DeidentifyContent(
        new DeidentifyContentRequest
        {
            ParentAsProjectName = new ProjectName(projectId),
            InspectConfig = new InspectConfig
            {
                InfoTypes = { infoTypes }
            },
            DeidentifyConfig = deidentifyConfig,
            Item = new ContentItem { Value = dataValue }
        });

    Console.WriteLine($"Deidentified content: {response.Item.Value}");
    return 0;
}

fixedSizeBucketingConfig

Las transformaciones de agrupamiento, esta y bucketingConfig, sirven para enmascarar datos numéricos mediante el “agrupamiento” en rangos. El rango numérico resultante es una string con guion que consta de un límite inferior, un guion y un límite superior.

Si configuras fixedSizeBucketingConfig en un objeto FixedSizeBucketingConfig se generan valores de entrada según rangos de tamaño fijo. El objeto FixedSizeBucketingConfig consta de los siguientes elementos:

  • lowerBound: el valor de límite inferior de todos los depósitos. Los valores menores que este se agrupan en un solo depósito.
  • upperBound: el valor de límite superior de todos los depósitos. Los valores mayores que este se agrupan en un solo depósito.
  • bucketSize: el tamaño de cada depósito que no sean los depósitos mínimos o máximos.

Por ejemplo, si lowerBound está configurado en 10, upperBound está configurado en 89, y bucketSize está configurado en 10, se usarán los siguientes depósitos: -10, 10-20, 20-30, 30-40, 40-50, 50-60, 60-70, 70-80, 80-89, 89+.

Para obtener más información sobre el concepto de agrupamiento, consulta Generalización y agrupamiento.

bucketingConfig

La transformación bucketingConfig ofrece más flexibilidad que la otra transformación de agrupamiento, fixedSizeBucketingConfig. En vez de especificar los límites inferiores y superiores y un valor interno con el que crear depósitos de igual tamaño, especificas los valores mínimos y máximos para cada depósito que desees crear. Cada par de valor mínimo y máximo debe tener el mismo tipo.

Si configuras bucketingConfig en un objeto BucketingConfig, se especifican depósitos personalizados. El objeto BucketingConfig consta de un arreglo buckets[] de objetos Bucket. Cada objeto Bucket consta de lo siguiente:

  • min: el límite inferior del rango del depósito. Omite este valor para crear un depósito que no tenga un límite inferior.
  • max: el límite superior del rango del depósito. Omite este valor para crear un depósito que no tenga un límite superior.
  • replacementValue: el valor con el que se reemplazan los valores que se encuentran dentro de los límites inferiores y superiores. Si no proporcionas un replacementValue, se usará un rango min-max con guion en su lugar.

Si un valor no se encuentra dentro de los rangos definidos, el TransformationSummary que se muestra contendrá un mensaje de error.

Por ejemplo, considera la siguiente configuración para la transformación bucketingConfig:

"bucketingConfig":{
  "buckets":[
    {
      "min":{
        "integerValue":"1"
      },
      "max":{
        "integerValue":"30"
      },
      "replacementValue":{
        "stringValue":"LOW"
      }
    },
    {
      "min":{
        "integerValue":"31"
      },
      "max":{
        "integerValue":"65"
      },
      "replacementValue":{
        "stringValue":"MEDIUM"
      }
    },
    {
      "min":{
        "integerValue":"66"
      },
      "max":{
        "integerValue":"100"
      },
      "replacementValue":{
        "stringValue":"HIGH"
      }
    }
  ]
}

Eso define el comportamiento siguiente:

  • Los valores de número entero que se encuentran entre 1 y 30 se enmascaran mediante el reemplazo por LOW.
  • Los valores de número entero que se encuentran entre 31 y 65 se enmascaran mediante el reemplazo por MEDIUM.
  • Los valores de número entero que se encuentran entre 66 y 100 se enmascaran mediante el reemplazo por HIGH.

Para obtener más información sobre el concepto de agrupamiento, consulta Generalización y agrupamiento.

replaceWithInfoTypeConfig

Si especificas replaceWithInfoTypeConfig, se reemplaza cada valor coincidente con el nombre del infotipo. El mensaje replaceWithInfoTypeConfig no tiene argumentos, si lo especificas se habilita su transformación.

Por ejemplo, supón que especificaste replaceWithInfoTypeConfig para todos los infotipos EMAIL_ADDRESS y la siguiente string se envía al Cloud DLP:

My name is Alicia Abernathy, and my email address is aabernathy@example.com.

La string obtenida será la que se muestra a continuación:

My name is Alicia Abernathy, and my email address is EMAIL_ADDRESS.
timePartConfig

Si configuras timePartConfig en un objeto TimePartConfig, se preserva una parte del valor coincidente que incluye los valores Date, Timestamp, y TimeOfDay. El objeto TimePartConfig consta de un argumento partToExtract, que se puede establecer en cualquiera de los valores enumerados de TimePart, que incluyen año, mes, día del mes, etcétera.

Por ejemplo, supón que configuraste una transformación timePartConfig cuando estableces partToExtract en YEAR. Después de enviar los datos de la primera columna inferior al Cloud DLP, tendrás los valores transformados en la segunda columna:

Valores originales Valores transformados
9/21/1976 1976
6/7/1945 1945
1/20/2009 2009
7/4/1776 1776
8/1/1984 1984
4/21/1982 1982

Transformaciones de registro

Las transformaciones de registro (el objeto RecordTransformations) se aplican solo a los valores dentro de los datos tabulares que se identifican como un infotipo específico. Dentro de RecordTransformations, existen dos subcategorías de transformaciones más, como se muestra a continuación:

  • fieldTransformations[]: transformaciones que aplican a varias transformaciones de campo.
  • recordSuppressions[]: reglas que definen qué registros se suprimen por completo. Los registros que coinciden con cualquier regla de supresión dentro de recordSuppressions[] se omiten desde la salida.

Transformaciones de campo

Cada objeto FieldTransformation incluye tres argumentos como los siguientes:

  • fields: uno o más campos de entrada (objetos FieldID) para aplicar a la transformación.
  • condition: una condición (un objeto RecordCondition) que se debe evaluar como verdadero para que la transformación se aplique. Por ejemplo, aplica una transformación de depósito a una columna de edad de un registro solo si la columna de código postal para el mismo registro se encuentra dentro de un rango específico. Otra opción es ocultar un campo solo si en el campo de fecha de nacimiento se pone la edad de una persona en 85 o más.
  • Uno de los siguientes dos argumentos de tipo de transformación. Debes especificar uno de ellos:

Supresión de registro

Además de aplicar transformaciones a los datos de campo, también puedes indicarle a Cloud DLP que desindentifique los datos mediante la supresión de registros cuando algunas condiciones de supresión se evalúen como verdaderas. Puedes aplicar las transformaciones de campo y las supresiones de registros en la misma solicitud.

Establece el mensaje recordSuppressions del objeto RecordTransformations para un arreglo de uno o más objetos RecordSuppression.

Cada objeto RecordSuppression consta de un solo objeto RecordCondition, que a la vez consta de un solo objeto Expressions.

Un objeto Expressions consta de lo siguiente:

  • logicalOperator: uno de los tipos enumerados de LogicalOperator.
  • conditions: un objeto Conditions, que consta de un arreglo de uno o más objetos Condition. Una Condition es una comparación de un valor de campo con otro valor, ambos son de tipo string, boolean, integer, double, Timestamp o TimeofDay.

Si la comparación se evalúa como verdadera, el registro se suprime y viceversa. Si los valores comparados no son del mismo tipo, se emite una advertencia y la condición se evalúa como false.

¿Te sirvió esta página? Envíanos tu opinión:

Enviar comentarios sobre…

Documentación sobre prevención de pérdida de datos