Proteger una base de datos con claves de cifrado gestionadas por el cliente (CMEK)

En esta página se describe cómo usar claves de encriptado gestionadas por el cliente (CMEK) creadas manualmente en Spanner.

Para obtener más información sobre las CMEKs, consulta el resumen de las claves de encriptado gestionadas por el cliente (CMEKs).

Crear una base de datos con CMEK habilitada

  1. Crea una clave en Cloud Key Management Service (Cloud KMS). Spanner admite la creación de los siguientes tipos de Cloud KMS:

    La clave debe estar en la misma ubicación que tu instancia de Spanner. Por ejemplo, si la configuración de tu instancia de Spanner está en us-west1, la ubicación del llavero de claves de Cloud KMS también debe ser us-west1.

    No todas las configuraciones de instancias multirregionales de Spanner tienen una ubicación de conjunto de claves de Cloud KMS correspondiente. En el caso de las bases de datos de Spanner con configuraciones de instancias personalizadas, birregionales o multirregionales, puedes usar varias claves regionales (de una sola región) de Cloud KMS para proteger tu base de datos. Por ejemplo:

    • Si tu base de datos de Spanner está en la configuración de instancia multirregión nam14, puedes crear claves de Cloud KMS en us-east4, northamerica-northeast1 y us-east1.
    • Si tu base de datos tiene una configuración de instancia personalizada que usa nam3 como configuración de instancia base con una réplica de solo lectura adicional en us-central2, puedes crear claves de Cloud KMS en us-east4, us-east1, us-central1 y us-central2.

    Opcional: Para ver una lista de las ubicaciones de las réplicas en la configuración de tu instancia de Spanner, usa el comando gcloud spanner instances get-locations:

    gcloud spanner instances get-locations <var>INSTANCE_ID</var>
    

    Para obtener más información, consulta los siguientes recursos:

  2. Concede acceso a Spanner a la clave.

    1. En Cloud Shell, crea y muestra el agente de servicio, o muéstralo si la cuenta ya existe:

      gcloud beta services identity create --service=spanner.googleapis.com \
          --project=PROJECT_ID

      Si se te pide que instales el componente gcloud Beta Commands, escribe Y. Después de la instalación, el comando se reinicia automáticamente.

      El comando gcloud services identity crea u obtiene el agente de servicio que Spanner puede usar para acceder a la clave de Cloud KMS en tu nombre.

      El ID de la cuenta de servicio tiene el formato de una dirección de correo electrónico:

      Service identity created: service-xxx@gcp-sa-spanner.iam.gserviceaccount.com
      
    2. Asigna el rol Encargado del encriptado y desencriptado de claves de CryptoKey de Cloud KMS(cloudkms.cryptoKeyEncrypterDecrypter) a la cuenta de servicio de cada región (--location) de la configuración de tu instancia de Spanner. Para ello, ejecuta el comando gcloud kms keys add-iam-policybinding:

      gcloud kms keys add-iam-policy-binding KMS_KEY \
          --location KMS_KEY_LOCATION \
          --keyring KMS_KEY_RING \
          --project=PROJECT_ID \
          --member serviceAccount:service-xxx@gcp-sa-spanner.iam.gserviceaccount.com \
          --role roles/cloudkms.cryptoKeyEncrypterDecrypter

      Este es un ejemplo de resultado:

      Updated IAM policy for key [KMS_KEY]
      

      Si usas varias claves de Cloud KMS para proteger tu base de datos, ejecuta el comando gcloud kms keys add-iam-policybinding para todas tus claves.

      Este rol asegura que la cuenta de servicio tenga permiso para encriptar y desencriptar con la clave de Cloud KMS. Para obtener más información, consulta Permisos y roles de Cloud KMS.

  3. Crea la base de datos y especifica tu clave de Cloud KMS.

Consola

Usa la consola para crear bases de datos en configuraciones de instancias regionales.

  1. En la consola, ve a la página Instancias. Google Cloud

    Ir a instancias de Spanner

  2. Haz clic en la instancia en la que quieras crear una base de datos.

  3. Haz clic en Crear base de datos y rellena los campos obligatorios.

  4. Haz clic en Mostrar opciones de cifrado.

  5. Selecciona Clave de Cloud KMS.

  6. Seleccione una clave de la lista desplegable.

    La lista de claves se limita al proyecto Google Cloud actual. Para usar una clave de otro proyecto, crea la base de datos con la CLI de gcloud en lugar de con la consola deGoogle Cloud . Google Cloud

    Una vez creada la base de datos, puede verificar que tiene habilitado CMEK en la página Resumen de la base de datos.

    Captura de pantalla que muestra el tipo de cifrado y la clave de una base de datos

gcloud

Para crear una base de datos con CMEK en una configuración de instancia regional, personalizada o multirregional, ejecuta el comando gcloud spanner databases create:

gcloud spanner databases create DATABASE \
  --project=SPANNER_PROJECT_ID \
  --instance=INSTANCE_ID \
  --ddl="CREATE TABLE Users (Id INT64 NOT NULL, FirstName STRING(100) NOT NULL, LastName STRING(100) NOT NULL,) PRIMARY KEY (Id)" \
  --kms-project=KMS_PROJECT_ID \
  --kms-location=KMS_KEY_LOCATION \
  --kms-keyring=KMS_KEYRING \
  --kms-keys=KMS_KEY_1[, KMS_KEY_2 ... ]

Para comprobar si una base de datos tiene habilitada la CMEK, ejecuta el comando gcloud spanner databases describe:

gcloud spanner databases describe DATABASE \
  --project=SPANNER_PROJECT_ID \
  --instance=INSTANCE_ID

Las bases de datos habilitadas para CMEK incluyen un campo para encryptionConfig, como se muestra en el siguiente ejemplo de salida:

encryptionConfig:
  kmsKeyNames:projects/my-kms-project/locations/eur5/keyRings/my-kms-key-ring/cryptoKeys/my-kms-key
  name: projects/my-spanner-project/instances/my-instance/databases/my-db
state: READY

Bibliotecas de cliente

C#

Para crear una base de datos con CMEK en una configuración de instancia regional, sigue estos pasos:


using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using System;
using System.Threading.Tasks;

public class CreateDatabaseWithEncryptionKeyAsyncSample
{
    public async Task<Database> CreateDatabaseWithEncryptionKeyAsync(string projectId, string instanceId, string databaseId, CryptoKeyName kmsKeyName)
    {
        // Create a DatabaseAdminClient instance that can be used to execute a
        // CreateDatabaseRequest with custom encryption configuration options.
        DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();
        // Define create table statement for table #1.
        var createSingersTable =
            @"CREATE TABLE Singers (
                SingerId INT64 NOT NULL,
                FirstName STRING(1024),
                LastName STRING(1024),
                ComposerInfo BYTES(MAX)
            ) PRIMARY KEY (SingerId)";
        // Define create table statement for table #2.
        var createAlbumsTable =
            @"CREATE TABLE Albums (
                SingerId INT64 NOT NULL,
                AlbumId INT64 NOT NULL,
                AlbumTitle STRING(MAX)
            ) PRIMARY KEY (SingerId, AlbumId),
            INTERLEAVE IN PARENT Singers ON DELETE CASCADE";

        // Create the CreateDatabase request with encryption configuration and execute it.
        var request = new CreateDatabaseRequest
        {
            ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId),
            CreateStatement = $"CREATE DATABASE `{databaseId}`",
            ExtraStatements = { createSingersTable, createAlbumsTable },
            EncryptionConfig = new EncryptionConfig
            {
                KmsKeyNameAsCryptoKeyName = kmsKeyName,
            },
        };
        var operation = await databaseAdminClient.CreateDatabaseAsync(request);

        // Wait until the operation has finished.
        Console.WriteLine("Waiting for the operation to finish.");
        var completedResponse = await operation.PollUntilCompletedAsync();
        if (completedResponse.IsFaulted)
        {
            Console.WriteLine($"Error while creating database: {completedResponse.Exception}");
            throw completedResponse.Exception;
        }

        var database = completedResponse.Result;
        Console.WriteLine($"Database {database.Name} created with encryption key {database.EncryptionConfig.KmsKeyName}");

        return database;
    }
}

Para crear una base de datos con CMEK en una configuración de instancia multirregional, sigue estos pasos:


using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class CreateDatabaseWithMultiRegionEncryptionAsyncSample
{
    public async Task<Database> CreateDatabaseWithMultiRegionEncryptionAsync(string projectId, string instanceId, string databaseId, IEnumerable<CryptoKeyName> kmsKeyNames)
    {
        // Create a DatabaseAdminClient instance that can be used to execute a
        // CreateDatabaseRequest with custom encryption configuration options.
        DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();
        // Define create table statement for table #1.
        var createSingersTable =
            @"CREATE TABLE Singers (
                SingerId INT64 NOT NULL,
                FirstName STRING(1024),
                LastName STRING(1024),
                ComposerInfo BYTES(MAX)
            ) PRIMARY KEY (SingerId)";
        // Define create table statement for table #2.
        var createAlbumsTable =
            @"CREATE TABLE Albums (
                SingerId INT64 NOT NULL,
                AlbumId INT64 NOT NULL,
                AlbumTitle STRING(MAX)
             ) PRIMARY KEY (SingerId, AlbumId),
             INTERLEAVE IN PARENT Singers ON DELETE CASCADE";

        // Create the CreateDatabase request with encryption configuration and execute it.
        var request = new CreateDatabaseRequest
        {
            ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId),
            CreateStatement = $"CREATE DATABASE `{databaseId}`",
            ExtraStatements = { createSingersTable, createAlbumsTable },
            EncryptionConfig = new EncryptionConfig
            {
                KmsKeyNamesAsCryptoKeyNames = { kmsKeyNames },
            },
        };
        var operation = await databaseAdminClient.CreateDatabaseAsync(request);

        // Wait until the operation has finished.
        Console.WriteLine("Waiting for the operation to finish.");
        var completedResponse = await operation.PollUntilCompletedAsync();
        if (completedResponse.IsFaulted)
        {
            Console.WriteLine($"Error while creating database: {completedResponse.Exception}");
            throw completedResponse.Exception;
        }

        var database = completedResponse.Result;
        Console.WriteLine($"Database {database.Name} created with encryption keys {string.Join(", ", kmsKeyNames)}");

        return database;
    }
}

C++

Para crear una base de datos con CMEK en una configuración de instancia regional, sigue estos pasos:

void CreateDatabaseWithEncryptionKey(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    std::string const& project_id, std::string const& instance_id,
    std::string const& database_id,
    google::cloud::KmsKeyName const& encryption_key) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  google::spanner::admin::database::v1::CreateDatabaseRequest request;
  request.set_parent(database.instance().FullName());
  request.set_create_statement("CREATE DATABASE `" + database.database_id() +
                               "`");
  request.add_extra_statements(R"""(
      CREATE TABLE Singers (
          SingerId   INT64 NOT NULL,
          FirstName  STRING(1024),
          LastName   STRING(1024),
          SingerInfo BYTES(MAX),
          FullName   STRING(2049)
              AS (ARRAY_TO_STRING([FirstName, LastName], " ")) STORED
      ) PRIMARY KEY (SingerId))""");
  request.add_extra_statements(R"""(
      CREATE TABLE Albums (
          SingerId     INT64 NOT NULL,
          AlbumId      INT64 NOT NULL,
          AlbumTitle   STRING(MAX)
      ) PRIMARY KEY (SingerId, AlbumId),
          INTERLEAVE IN PARENT Singers ON DELETE CASCADE)""");
  request.mutable_encryption_config()->set_kms_key_name(
      encryption_key.FullName());
  auto db = client.CreateDatabase(request).get();
  if (!db) throw std::move(db).status();
  std::cout << "Database " << db->name() << " created";
  std::cout << " using encryption key " << encryption_key.FullName();
  std::cout << ".\n";
}

Para crear una base de datos con CMEK en una configuración de instancia multirregional, sigue estos pasos:

void CreateDatabaseWithMRCMEK(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    std::string const& project_id, std::string const& instance_id,
    std::string const& database_id,
    std::vector<google::cloud::KmsKeyName> const& encryption_keys) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  google::spanner::admin::database::v1::CreateDatabaseRequest request;
  request.set_parent(database.instance().FullName());
  request.set_create_statement("CREATE DATABASE `" + database.database_id() +
                               "`");
  request.add_extra_statements(R"""(
      CREATE TABLE Singers (
          SingerId   INT64 NOT NULL,
          FirstName  STRING(1024),
          LastName   STRING(1024),
          SingerInfo BYTES(MAX),
          FullName   STRING(2049)
              AS (ARRAY_TO_STRING([FirstName, LastName], " ")) STORED
      ) PRIMARY KEY (SingerId))""");
  request.add_extra_statements(R"""(
      CREATE TABLE Albums (
          SingerId     INT64 NOT NULL,
          AlbumId      INT64 NOT NULL,
          AlbumTitle   STRING(MAX)
      ) PRIMARY KEY (SingerId, AlbumId),
          INTERLEAVE IN PARENT Singers ON DELETE CASCADE)""");
  for (google::cloud::KmsKeyName const& encryption_key : encryption_keys) {
    request.mutable_encryption_config()->add_kms_key_names(
        encryption_key.FullName());
  }
  auto db = client.CreateDatabase(request).get();
  if (!db) throw std::move(db).status();
  std::cout << "Database " << db->name() << " created";
  PrintKmsKeys(encryption_keys);
}

Go

Para crear una base de datos con CMEK en una configuración de instancia regional, sigue estos pasos:

import (
	"context"
	"fmt"
	"io"
	"regexp"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
)

func createDatabaseWithCustomerManagedEncryptionKey(ctx context.Context, w io.Writer, db, kmsKeyName string) error {
	// db = `projects/<project>/instances/<instance-id>/database/<database-id>`
	// kmsKeyName = `projects/<project>/locations/<location>/keyRings/<key_ring>/cryptoKeys/<kms_key_name>`
	matches := regexp.MustCompile("^(.+)/databases/(.+)$").FindStringSubmatch(db)
	if matches == nil || len(matches) != 3 {
		return fmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey: invalid database id %q", db)
	}
	instanceName := matches[1]
	databaseId := matches[2]

	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return fmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey.NewDatabaseAdminClient: %w", err)
	}
	defer adminClient.Close()

	// Create a database with tables using a Customer Managed Encryption Key
	req := adminpb.CreateDatabaseRequest{
		Parent:          instanceName,
		CreateStatement: "CREATE DATABASE `" + databaseId + "`",
		ExtraStatements: []string{
			`CREATE TABLE Singers (
				SingerId   INT64 NOT NULL,
				FirstName  STRING(1024),
				LastName   STRING(1024),
				SingerInfo BYTES(MAX)
			) PRIMARY KEY (SingerId)`,
			`CREATE TABLE Albums (
				SingerId     INT64 NOT NULL,
				AlbumId      INT64 NOT NULL,
				AlbumTitle   STRING(MAX)
			) PRIMARY KEY (SingerId, AlbumId),
			INTERLEAVE IN PARENT Singers ON DELETE CASCADE`,
		},
		EncryptionConfig: &adminpb.EncryptionConfig{KmsKeyName: kmsKeyName},
	}
	op, err := adminClient.CreateDatabase(ctx, &req)
	if err != nil {
		return fmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey.CreateDatabase: %w", err)
	}
	dbObj, err := op.Wait(ctx)
	if err != nil {
		return fmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey.Wait: %w", err)
	}
	fmt.Fprintf(w, "Created database [%s] using encryption key %q\n", dbObj.Name, dbObj.EncryptionConfig.KmsKeyName)
	return nil
}

Para crear una base de datos con CMEK en una configuración de instancia multirregional, sigue estos pasos:


import (
	"context"
	"fmt"
	"io"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
)

// createDatabaseWithCustomerManagedMultiRegionEncryptionKey creates a new database with tables using a Customer Managed Multi-Region Encryption Key.
func createDatabaseWithCustomerManagedMultiRegionEncryptionKey(ctx context.Context, w io.Writer, projectID, instanceID, databaseID string, kmsKeyNames []string) error {
	// projectID = `my-project`
	// instanceID = `my-instance`
	// databaseID = `my-database`
	// kmsKeyNames := []string{"projects/my-project/locations/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	//	 "projects/my-project/locations/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	//	 "projects/my-project/locations/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	// }

	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return fmt.Errorf("createDatabaseWithCustomerManagedMultiRegionEncryptionKey.NewDatabaseAdminClient: %w", err)
	}
	defer adminClient.Close()

	// Create a database with tables using a Customer Managed Multi-Region Encryption Key
	req := adminpb.CreateDatabaseRequest{
		Parent:          fmt.Sprintf("projects/%s/instances/%s", projectID, instanceID),
		CreateStatement: "CREATE DATABASE `" + databaseID + "`",
		ExtraStatements: []string{
			`CREATE TABLE Singers (
				SingerId   INT64 NOT NULL,
				FirstName  STRING(1024),
				LastName   STRING(1024),
				SingerInfo BYTES(MAX)
			) PRIMARY KEY (SingerId)`,
			`CREATE TABLE Albums (
				SingerId     INT64 NOT NULL,
				AlbumId      INT64 NOT NULL,
				AlbumTitle   STRING(MAX)
			) PRIMARY KEY (SingerId, AlbumId),
			INTERLEAVE IN PARENT Singers ON DELETE CASCADE`,
		},
		EncryptionConfig: &adminpb.EncryptionConfig{KmsKeyNames: kmsKeyNames},
	}
	op, err := adminClient.CreateDatabase(ctx, &req)
	if err != nil {
		return fmt.Errorf("createDatabaseWithCustomerManagedMultiRegionEncryptionKey.CreateDatabase: %w", err)
	}
	dbObj, err := op.Wait(ctx)
	if err != nil {
		return fmt.Errorf("createDatabaseWithCustomerManagedMultiRegionEncryptionKey.Wait: %w", err)
	}
	fmt.Fprintf(w, "Created database [%s] using multi-region encryption keys %q\n", dbObj.Name, dbObj.EncryptionConfig.GetKmsKeyNames())
	return nil
}

Java

Para crear una base de datos con CMEK en una configuración de instancia regional, sigue estos pasos:


import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
import com.google.spanner.admin.database.v1.Database;
import com.google.spanner.admin.database.v1.EncryptionConfig;
import com.google.spanner.admin.database.v1.InstanceName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateDatabaseWithEncryptionKey {

  static void createDatabaseWithEncryptionKey() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String kmsKeyName =
        "projects/" + projectId + "/locations/<location>/keyRings/<keyRing>/cryptoKeys/<keyId>";

    try (Spanner spanner =
        SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
      createDatabaseWithEncryptionKey(
          adminClient,
          projectId,
          instanceId,
          databaseId,
          kmsKeyName);
    }
  }

  static void createDatabaseWithEncryptionKey(DatabaseAdminClient adminClient,
      String projectId, String instanceId, String databaseId, String kmsKeyName) {
    InstanceName instanceName = InstanceName.of(projectId, instanceId);
    CreateDatabaseRequest request = CreateDatabaseRequest.newBuilder()
        .setParent(instanceName.toString())
        .setCreateStatement("CREATE DATABASE `" + databaseId + "`")
        .setEncryptionConfig(EncryptionConfig.newBuilder().setKmsKeyName(kmsKeyName).build())
        .addAllExtraStatements(
            ImmutableList.of(
                "CREATE TABLE Singers ("
                    + "  SingerId   INT64 NOT NULL,"
                    + "  FirstName  STRING(1024),"
                    + "  LastName   STRING(1024),"
                    + "  SingerInfo BYTES(MAX)"
                    + ") PRIMARY KEY (SingerId)",
                "CREATE TABLE Albums ("
                    + "  SingerId     INT64 NOT NULL,"
                    + "  AlbumId      INT64 NOT NULL,"
                    + "  AlbumTitle   STRING(MAX)"
                    + ") PRIMARY KEY (SingerId, AlbumId),"
                    + "  INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
            ))
        .build();
    try {
      System.out.println("Waiting for operation to complete...");
      Database createdDatabase =
          adminClient.createDatabaseAsync(request).get(120, TimeUnit.SECONDS);

      System.out.printf(
          "Database %s created with encryption key %s%n",
          createdDatabase.getName(),
          createdDatabase.getEncryptionConfig().getKmsKeyName()
      );
    } catch (ExecutionException e) {
      // If the operation failed during execution, expose the cause.
      throw SpannerExceptionFactory.asSpannerException(e.getCause());
    } catch (InterruptedException e) {
      // Throw when a thread is waiting, sleeping, or otherwise occupied,
      // and the thread is interrupted, either before or during the activity.
      throw SpannerExceptionFactory.propagateInterrupt(e);
    } catch (TimeoutException e) {
      // If the operation timed out propagates the timeout
      throw SpannerExceptionFactory.propagateTimeout(e);
    }
  }
}

Para crear una base de datos con CMEK en una configuración de instancia multirregional, sigue estos pasos:


import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
import com.google.spanner.admin.database.v1.Database;
import com.google.spanner.admin.database.v1.EncryptionConfig;
import com.google.spanner.admin.database.v1.InstanceName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CreateDatabaseWithMultiRegionEncryptionKey {

  static void createDatabaseWithEncryptionKey() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String[] kmsKeyNames =
        new String[] {
          "projects/" + projectId + "/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
          "projects/" + projectId + "/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
          "projects/" + projectId + "/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>"
        };
    try (Spanner spanner =
            SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
      createDatabaseWithMultiRegionEncryptionKey(
          adminClient, projectId, instanceId, databaseId, kmsKeyNames);
    }
  }

  static void createDatabaseWithMultiRegionEncryptionKey(
      DatabaseAdminClient adminClient,
      String projectId,
      String instanceId,
      String databaseId,
      String[] kmsKeyNames) {
    InstanceName instanceName = InstanceName.of(projectId, instanceId);
    CreateDatabaseRequest request =
        CreateDatabaseRequest.newBuilder()
            .setParent(instanceName.toString())
            .setCreateStatement("CREATE DATABASE `" + databaseId + "`")
            .setEncryptionConfig(
                EncryptionConfig.newBuilder()
                    .addAllKmsKeyNames(ImmutableList.copyOf(kmsKeyNames))
                    .build())
            .addAllExtraStatements(
                ImmutableList.of(
                    "CREATE TABLE Singers ("
                        + "  SingerId   INT64 NOT NULL,"
                        + "  FirstName  STRING(1024),"
                        + "  LastName   STRING(1024),"
                        + "  SingerInfo BYTES(MAX)"
                        + ") PRIMARY KEY (SingerId)",
                    "CREATE TABLE Albums ("
                        + "  SingerId     INT64 NOT NULL,"
                        + "  AlbumId      INT64 NOT NULL,"
                        + "  AlbumTitle   STRING(MAX)"
                        + ") PRIMARY KEY (SingerId, AlbumId),"
                        + "  INTERLEAVE IN PARENT Singers ON DELETE CASCADE"))
            .build();
    try {
      System.out.println("Waiting for operation to complete...");
      Database createdDatabase =
          adminClient.createDatabaseAsync(request).get(120, TimeUnit.SECONDS);

      System.out.printf(
          "Database %s created with encryption keys %s%n",
          createdDatabase.getName(), createdDatabase.getEncryptionConfig().getKmsKeyNamesList());
    } catch (ExecutionException e) {
      // If the operation failed during execution, expose the cause.
      throw SpannerExceptionFactory.asSpannerException(e.getCause());
    } catch (InterruptedException e) {
      // Throw when a thread is waiting, sleeping, or otherwise occupied,
      // and the thread is interrupted, either before or during the activity.
      throw SpannerExceptionFactory.propagateInterrupt(e);
    } catch (TimeoutException e) {
      // If the operation timed out propagates the timeout
      throw SpannerExceptionFactory.propagateTimeout(e);
    }
  }
}

Node.js

Para crear una base de datos con CMEK en una configuración de instancia regional, sigue estos pasos:


// Imports the Google Cloud client library
const {Spanner, protos} = require('@google-cloud/spanner');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const keyName =
//   'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key';

// creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner Database Admin Client object
const databaseAdminClient = spanner.getDatabaseAdminClient();

// Creates a database
const [operation] = await databaseAdminClient.createDatabase({
  createStatement: 'CREATE DATABASE `' + databaseId + '`',
  parent: databaseAdminClient.instancePath(projectId, instanceId),
  encryptionConfig:
    (protos.google.spanner.admin.database.v1.EncryptionConfig = {
      kmsKeyName: keyName,
    }),
});

console.log(`Waiting for operation on ${databaseId} to complete...`);
await operation.promise();

console.log(`Created database ${databaseId} on instance ${instanceId}.`);

// Get encryption key
const [metadata] = await databaseAdminClient.getDatabase({
  name: databaseAdminClient.databasePath(projectId, instanceId, databaseId),
});

console.log(
  `Database encrypted with key ${metadata.encryptionConfig.kmsKeyName}.`,
);

Para crear una base de datos con CMEK en una configuración de instancia multirregional, sigue estos pasos:

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const kmsKeyNames =
//   'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key1,projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key2';

// Imports the Google Cloud client library
const {Spanner, protos} = require('@google-cloud/spanner');

// creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner Database Admin Client object
const databaseAdminClient = spanner.getDatabaseAdminClient();

async function createDatabaseWithMultipleKmsKeys() {
  // Creates a database
  const [operation] = await databaseAdminClient.createDatabase({
    createStatement: 'CREATE DATABASE `' + databaseId + '`',
    parent: databaseAdminClient.instancePath(projectId, instanceId),
    encryptionConfig:
      (protos.google.spanner.admin.database.v1.EncryptionConfig = {
        kmsKeyNames: kmsKeyNames.split(','),
      }),
  });

  console.log(`Waiting for operation on ${databaseId} to complete...`);
  await operation.promise();

  console.log(`Created database ${databaseId} on instance ${instanceId}.`);

  // Get encryption key
  const [metadata] = await databaseAdminClient.getDatabase({
    name: databaseAdminClient.databasePath(projectId, instanceId, databaseId),
  });

  console.log(
    `Database encrypted with keys ${metadata.encryptionConfig.kmsKeyNames}.`,
  );
}
createDatabaseWithMultipleKmsKeys();

PHP

Para crear una base de datos con CMEK en una configuración de instancia regional, sigue estos pasos:

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\CreateDatabaseRequest;
use Google\Cloud\Spanner\Admin\Database\V1\EncryptionConfig;

/**
 * Creates an encrypted database with tables for sample data.
 * Example:
 * ```
 * create_database_with_encryption_key($projectId, $instanceId, $databaseId, $kmsKeyName);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 * @param string $kmsKeyName The KMS key used for encryption.
 */
function create_database_with_encryption_key(
    string $projectId,
    string $instanceId,
    string $databaseId,
    string $kmsKeyName
): void {
    $databaseAdminClient = new DatabaseAdminClient();
    $instanceName = DatabaseAdminClient::instanceName($projectId, $instanceId);

    $createDatabaseRequest = new CreateDatabaseRequest();
    $createDatabaseRequest->setParent($instanceName);
    $createDatabaseRequest->setCreateStatement(sprintf('CREATE DATABASE `%s`', $databaseId));
    $createDatabaseRequest->setExtraStatements([
        'CREATE TABLE Singers (
            SingerId     INT64 NOT NULL,
            FirstName    STRING(1024),
            LastName     STRING(1024),
            SingerInfo   BYTES(MAX)
        ) PRIMARY KEY (SingerId)',
        'CREATE TABLE Albums (
            SingerId     INT64 NOT NULL,
            AlbumId      INT64 NOT NULL,
            AlbumTitle   STRING(MAX)
        ) PRIMARY KEY (SingerId, AlbumId),
        INTERLEAVE IN PARENT Singers ON DELETE CASCADE'
    ]);

    if (!empty($kmsKeyName)) {
        $encryptionConfig = new EncryptionConfig();
        $encryptionConfig->setKmsKeyName($kmsKeyName);
        $createDatabaseRequest->setEncryptionConfig($encryptionConfig);
    }

    $operationResponse = $databaseAdminClient->createDatabase($createDatabaseRequest);
    printf('Waiting for operation to complete...' . PHP_EOL);
    $operationResponse->pollUntilComplete();

    if ($operationResponse->operationSucceeded()) {
        $database = $operationResponse->getResult();
        printf(
            'Created database %s on instance %s with encryption key %s' . PHP_EOL,
            $databaseId,
            $instanceId,
            $database->getEncryptionConfig()->getKmsKeyName()
        );
    } else {
        $error = $operationResponse->getError();
        printf('Failed to create encrypted database: %s' . PHP_EOL, $error->getMessage());
    }
}

Para crear una base de datos con CMEK en una configuración de instancia multirregional, sigue estos pasos:

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\CreateDatabaseRequest;
use Google\Cloud\Spanner\Admin\Database\V1\EncryptionConfig;

/**
 * Creates a MR CMEK database with tables for sample data.
 * Example:
 * ```
 * create_database_with_mr_cmek($projectId, $instanceId, $databaseId, $kmsKeyNames);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 * @param string[] $kmsKeyNames The KMS keys used for encryption.
 */
function create_database_with_mr_cmek(
    string $projectId,
    string $instanceId,
    string $databaseId,
    array $kmsKeyNames
): void {
    $databaseAdminClient = new DatabaseAdminClient();
    $instanceName = DatabaseAdminClient::instanceName($projectId, $instanceId);

    $createDatabaseRequest = new CreateDatabaseRequest();
    $createDatabaseRequest->setParent($instanceName);
    $createDatabaseRequest->setCreateStatement(sprintf('CREATE DATABASE `%s`', $databaseId));
    $createDatabaseRequest->setExtraStatements([
        'CREATE TABLE Singers (
            SingerId     INT64 NOT NULL,
            FirstName    STRING(1024),
            LastName     STRING(1024),
            SingerInfo   BYTES(MAX)
        ) PRIMARY KEY (SingerId)',
        'CREATE TABLE Albums (
            SingerId     INT64 NOT NULL,
            AlbumId      INT64 NOT NULL,
            AlbumTitle   STRING(MAX)
        ) PRIMARY KEY (SingerId, AlbumId),
        INTERLEAVE IN PARENT Singers ON DELETE CASCADE'
    ]);

    if (!empty($kmsKeyNames)) {
        $encryptionConfig = new EncryptionConfig();
        $encryptionConfig->setKmsKeyNames($kmsKeyNames);
        $createDatabaseRequest->setEncryptionConfig($encryptionConfig);
    }

    $operationResponse = $databaseAdminClient->createDatabase($createDatabaseRequest);
    printf('Waiting for operation to complete...' . PHP_EOL);
    $operationResponse->pollUntilComplete();

    if ($operationResponse->operationSucceeded()) {
        $database = $operationResponse->getResult();
        printf(
            'Created database %s on instance %s with encryption keys %s' . PHP_EOL,
            $databaseId,
            $instanceId,
            print_r($database->getEncryptionConfig()->getKmsKeyNames(), true)
        );
    } else {
        $error = $operationResponse->getError();
        printf('Failed to create encrypted database: %s' . PHP_EOL, $error->getMessage());
    }
}

Python

Para crear una base de datos con CMEK en una configuración de instancia regional, sigue estos pasos:

def create_database_with_encryption_key(instance_id, database_id, kms_key_name):
    """Creates a database with tables using a Customer Managed Encryption Key (CMEK)."""
    from google.cloud.spanner_admin_database_v1 import EncryptionConfig
    from google.cloud.spanner_admin_database_v1.types import spanner_database_admin

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    request = spanner_database_admin.CreateDatabaseRequest(
        parent=database_admin_api.instance_path(spanner_client.project, instance_id),
        create_statement=f"CREATE DATABASE `{database_id}`",
        extra_statements=[
            """CREATE TABLE Singers (
            SingerId     INT64 NOT NULL,
            FirstName    STRING(1024),
            LastName     STRING(1024),
            SingerInfo   BYTES(MAX)
        ) PRIMARY KEY (SingerId)""",
            """CREATE TABLE Albums (
            SingerId     INT64 NOT NULL,
            AlbumId      INT64 NOT NULL,
            AlbumTitle   STRING(MAX)
        ) PRIMARY KEY (SingerId, AlbumId),
        INTERLEAVE IN PARENT Singers ON DELETE CASCADE""",
        ],
        encryption_config=EncryptionConfig(kms_key_name=kms_key_name),
    )

    operation = database_admin_api.create_database(request=request)

    print("Waiting for operation to complete...")
    database = operation.result(OPERATION_TIMEOUT_SECONDS)

    print(
        "Database {} created with encryption key {}".format(
            database.name, database.encryption_config.kms_key_name
        )
    )

Para crear una base de datos con CMEK en una configuración de instancia multirregional, sigue estos pasos:

def create_database_with_multiple_kms_keys(instance_id, database_id, kms_key_names):
    """Creates a database with tables using multiple KMS keys(CMEK)."""
    from google.cloud.spanner_admin_database_v1 import EncryptionConfig
    from google.cloud.spanner_admin_database_v1.types import spanner_database_admin

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    request = spanner_database_admin.CreateDatabaseRequest(
        parent=database_admin_api.instance_path(spanner_client.project, instance_id),
        create_statement=f"CREATE DATABASE `{database_id}`",
        extra_statements=[
            """CREATE TABLE Singers (
            SingerId     INT64 NOT NULL,
            FirstName    STRING(1024),
            LastName     STRING(1024),
            SingerInfo   BYTES(MAX)
        ) PRIMARY KEY (SingerId)""",
            """CREATE TABLE Albums (
            SingerId     INT64 NOT NULL,
            AlbumId      INT64 NOT NULL,
            AlbumTitle   STRING(MAX)
        ) PRIMARY KEY (SingerId, AlbumId),
        INTERLEAVE IN PARENT Singers ON DELETE CASCADE""",
        ],
        encryption_config=EncryptionConfig(kms_key_names=kms_key_names),
    )

    operation = database_admin_api.create_database(request=request)

    print("Waiting for operation to complete...")
    database = operation.result(OPERATION_TIMEOUT_SECONDS)

    print(
        "Database {} created with multiple KMS keys {}".format(
            database.name, database.encryption_config.kms_key_names
        )
    )

Ruby

Para crear una base de datos con CMEK en una configuración de instancia regional, sigue estos pasos:

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
# kms_key_name = "Database eencryption KMS key"

require "google/cloud/spanner"
require "google/cloud/spanner/admin/database"

database_admin_client = Google::Cloud::Spanner::Admin::Database.database_admin

instance_path = database_admin_client.instance_path project: project_id, instance: instance_id

db_path = database_admin_client.database_path project: project_id,
                                              instance: instance_id,
                                              database: database_id

job = database_admin_client.create_database parent: instance_path,
                                            create_statement: "CREATE DATABASE `#{database_id}`",
                                            extra_statements: [
                                              "CREATE TABLE Singers (
                                   SingerId     INT64 NOT NULL,
                                   FirstName    STRING(1024),
                                   LastName     STRING(1024),
                                   SingerInfo   BYTES(MAX)
                                 ) PRIMARY KEY (SingerId)",

                                              "CREATE TABLE Albums (
                                   SingerId     INT64 NOT NULL,
                                   AlbumId      INT64 NOT NULL,
                                   AlbumTitle   STRING(MAX)
                                 ) PRIMARY KEY (SingerId, AlbumId),
                                 INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
                                            ],
                                            encryption_config: { kms_key_name: kms_key_name }

puts "Waiting for create database operation to complete"

job.wait_until_done!
database = database_admin_client.get_database name: db_path

puts "Database #{database_id} created with encryption key #{database.encryption_config.kms_key_name}"

Para crear una base de datos con CMEK en una configuración de instancia multirregional, sigue estos pasos:

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
# kms_key_names = ["key1", "key2", "key3"]

require "google/cloud/spanner"
require "google/cloud/spanner/admin/database"

database_admin_client = Google::Cloud::Spanner::Admin::Database.database_admin

instance_path = database_admin_client.instance_path(
  project: project_id, instance: instance_id
)

encryption_config = {
  kms_key_names: kms_key_names
}

db_path = database_admin_client.database_path(
  project: project_id,
  instance: instance_id,
  database: database_id
)

job = database_admin_client.create_database(
  parent: instance_path,
  create_statement: "CREATE DATABASE `#{database_id}`",
  extra_statements: [
    <<~STATEMENT,
      CREATE TABLE Singers (
        SingerId    INT64 NOT NULL,
        FirstName   STRING(1024),
        LastName    STRING(1024),
        SingerInfo  BYTES(MAX)
      ) PRIMARY KEY (SingerId)
    STATEMENT
    <<~STATEMENT
      CREATE TABLE Albums (
        SingerId    INT64 NOT NULL,
        AlbumId     INT64 NOT NULL,
        AlbumTitle  STRING(MAX)
      ) PRIMARY KEY (SingerId, AlbumId),
      INTERLEAVE IN PARENT Singers
      ON DELETE CASCADE
    STATEMENT
  ],
  encryption_config: encryption_config
)

puts "Waiting for create database operation to complete"

job.wait_until_done!
database = database_admin_client.get_database name: db_path

puts "Database #{database_id} created with encryption key " \
     "#{database.encryption_config.kms_key_names}"

Ver las versiones de clave en uso

El campo encryption_info de la base de datos muestra información sobre las versiones clave.

Cuando cambia la versión de la clave de una base de datos, el cambio no se propaga inmediatamente a encryption_info. Puede que el cambio tarde en reflejarse en este campo.

Consola

  1. En la consola, ve a la página Instancias. Google Cloud

    Ir a Instancias

  2. Haga clic en la instancia que contiene la base de datos que quiere ver.

  3. Haz clic en la base de datos.

    La información de cifrado se muestra en la página Detalles de la base de datos.

    Captura de pantalla de la información de cifrado que se muestra en la página de detalles de la base de datos.

gcloud

Puedes obtener el encryption_info de una base de datos ejecutando el comando gcloud spanner databases describe o gcloud spanner databases list. Por ejemplo:

gcloud spanner databases describe DATABASE \
    --project=SPANNER_PROJECT_ID \
    --instance=INSTANCE_ID

Este es un ejemplo de resultado:

name: projects/my-project/instances/test-instance/databases/example-db
encryptionInfo:
- encryptionType: CUSTOMER_MANAGED_ENCRYPTION
  kmsKeyVersion: projects/my-kms-project/locations/my-kms-key1-location/keyRings/my-kms-key-ring1/cryptoKeys/my-kms-key1/cryptoKeyVersions/1
- encryptionType: CUSTOMER_MANAGED_ENCRYPTION
  kmsKeyVersion: projects/my-kms-project/locations/my-kms-key2-location/keyRings/my-kms-key-ring2/cryptoKeys/my-kms-key2/cryptoKeyVersions/1

Inhabilita la clave

  1. Inhabilita las versiones de clave que estén en uso siguiendo estas instrucciones para cada versión de clave.

  2. Espera a que se aplique el cambio. La inhabilitación de una clave puede tardar hasta tres horas en propagarse.

  3. Para confirmar que ya no se puede acceder a la base de datos, ejecuta una consulta en la base de datos con CMEK inhabilitada:

    gcloud spanner databases execute-sql DATABASE \
        --project=SPANNER_PROJECT_ID \
        --instance=INSTANCE_ID \
        --sql='SELECT * FROM Users'

    Aparece el siguiente mensaje de error: KMS key required by the Spanner resource is not accessible.

Habilita la clave

  1. Habilita las versiones de clave que usa la base de datos siguiendo estas instrucciones para cada versión de clave.

  2. Espera a que se aplique el cambio. La habilitación de una clave puede tardar hasta tres horas en propagarse.

  3. Para confirmar que ya no se puede acceder a la base de datos, ejecuta una consulta en la base de datos habilitada para CMEK:

    gcloud spanner databases execute-sql DATABASE \
        --project=SPANNER_PROJECT_ID \
        --instance=INSTANCE_ID \
        --sql='SELECT * FROM Users'

    Si el cambio se ha aplicado, el comando se ejecutará correctamente.

Crear una copia de seguridad de una base de datos

Puede usar las copias de seguridad de Spanner para crear copias de seguridad de sus bases de datos. De forma predeterminada, las copias de seguridad de Spanner creadas a partir de una base de datos usan la misma configuración de cifrado que la propia base de datos. También puedes especificar una configuración de cifrado diferente para una copia de seguridad.

Consola

Usa la consola para crear copias de seguridad en configuraciones de instancias regionales.

  1. En la consola, ve a la página Instancias. Google Cloud

    Ir a instancias de Spanner

  2. Haga clic en el nombre de la instancia que contiene la base de datos de la que quiere crear una copia de seguridad.

  3. Haz clic en la base de datos.

  4. En el panel de navegación, haz clic en Copia de seguridad o restauración.

  5. En la pestaña Copias de seguridad, haz clic en Crear copia de seguridad.

  6. Escribe un nombre para la copia de seguridad y selecciona una fecha de vencimiento.

  7. Opcional: Haz clic en Mostrar opciones de cifrado.

    a. Si quieres usar otra configuración de cifrado para tu copia de seguridad, haz clic en el control deslizante situado junto a Usar cifrado actual.

    a. Selecciona Clave de Cloud KMS.

    a. Seleccione una clave de la lista desplegable.

    La lista de claves se limita al proyecto Google Cloud actual. Para usar una clave de otro proyecto, crea la base de datos con la CLI de gcloud en lugar de con la consola. Google Cloud Google Cloud

  8. Haz clic en Crear.

En la tabla Copias de seguridad se muestra información sobre el cifrado de cada copia de seguridad.

Captura de pantalla de la tabla Copias de seguridad que muestra la información de cifrado de cada copia de seguridad

gcloud

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, personalizada o multirregional, ejecuta el comando gcloud spanner backups create:

gcloud spanner backups create BACKUP \
    --project=SPANNER_PROJECT_ID \
    --instance=INSTANCE_ID \
    --database=DATABASE  \
    --retention-period=RETENTION_PERIOD  \
    --encryption-type=customer_managed_encryption \
    --kms-project=KMS_PROJECT_ID \
    --kms-location=KMS_KEY_LOCATION \
    --kms-keyring=KMS_KEY_RING \
    --kms-keys=KMS_KEY_1[, KMS_KEY_2 ... ]
    --async

Para verificar que la copia de seguridad creada está cifrada con CMEK, sigue estos pasos:

gcloud spanner backups describe BACKUP \
    --project=SPANNER_PROJECT_ID \
    --instance=INSTANCE_ID

Bibliotecas de cliente

C#

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, sigue estos pasos:


using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using Google.Protobuf.WellKnownTypes;
using System;
using System.Threading.Tasks;

public class CreateBackupWithEncryptionKeyAsyncSample
{
    public async Task<Backup> CreateBackupWithEncryptionKeyAsync(string projectId, string instanceId, string databaseId, string backupId, CryptoKeyName kmsKeyName)
    {
        // Create a DatabaseAdminClient instance.
        DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();

        // Create the CreateBackupRequest with encryption configuration.
        CreateBackupRequest request = new CreateBackupRequest
        {
            ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId),
            BackupId = backupId,
            Backup = new Backup
            {
                DatabaseAsDatabaseName = DatabaseName.FromProjectInstanceDatabase(projectId, instanceId, databaseId),
                ExpireTime = DateTime.UtcNow.AddDays(14).ToTimestamp(),
            },
            EncryptionConfig = new CreateBackupEncryptionConfig
            {
                EncryptionType = CreateBackupEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,
                KmsKeyNameAsCryptoKeyName = kmsKeyName,
            },
        };
        // Execute the CreateBackup request.
        var operation = await databaseAdminClient.CreateBackupAsync(request);

        Console.WriteLine("Waiting for the operation to finish.");

        // Poll until the returned long-running operation is complete.
        var completedResponse = await operation.PollUntilCompletedAsync();
        if (completedResponse.IsFaulted)
        {
            Console.WriteLine($"Error while creating backup: {completedResponse.Exception}");
            throw completedResponse.Exception;
        }

        var backup = completedResponse.Result;
        Console.WriteLine($"Backup {backup.Name} of size {backup.SizeBytes} bytes " +
                      $"was created at {backup.CreateTime} " +
                      $"using encryption key {kmsKeyName}");
        return backup;
    }
}

Para crear una copia de seguridad con CMEK en una configuración de instancia multirregional, sigue estos pasos:


using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using Google.Protobuf.WellKnownTypes;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class CreateBackupWithMultiRegionEncryptionAsyncSample
{
    public async Task<Backup> CreateBackupWithMultiRegionEncryptionAsync(string projectId, string instanceId, string databaseId, string backupId, IEnumerable<CryptoKeyName> kmsKeyNames)
    {
        // Create a DatabaseAdminClient instance.
        DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();

        // Create the CreateBackupRequest with encryption configuration.
        CreateBackupRequest request = new CreateBackupRequest
        {
            ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId),
            BackupId = backupId,
            Backup = new Backup
            {
                DatabaseAsDatabaseName = DatabaseName.FromProjectInstanceDatabase(projectId, instanceId, databaseId),
                ExpireTime = DateTime.UtcNow.AddDays(14).ToTimestamp(),
            },
            EncryptionConfig = new CreateBackupEncryptionConfig
            {
                EncryptionType = CreateBackupEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,
                KmsKeyNamesAsCryptoKeyNames = { kmsKeyNames },
            },
        };
        // Execute the CreateBackup request.
        var operation = await databaseAdminClient.CreateBackupAsync(request);

        Console.WriteLine("Waiting for the operation to finish.");

        // Poll until the returned long-running operation is complete.
        var completedResponse = await operation.PollUntilCompletedAsync();
        if (completedResponse.IsFaulted)
        {
            Console.WriteLine($"Error while creating backup: {completedResponse.Exception}");
            throw completedResponse.Exception;
        }

        var backup = completedResponse.Result;
        Console.WriteLine($"Backup {backup.Name} of size {backup.SizeBytes} bytes was created with encryption keys {string.Join(", ", kmsKeyNames)} at {backup.CreateTime}");
        return backup;
    }
}

C++

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, sigue estos pasos:

void CreateBackupWithEncryptionKey(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    std::string const& project_id, std::string const& instance_id,
    std::string const& database_id, std::string const& backup_id,
    google::cloud::spanner::Timestamp expire_time,
    google::cloud::spanner::Timestamp version_time,
    google::cloud::KmsKeyName const& encryption_key) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  google::spanner::admin::database::v1::CreateBackupRequest request;
  request.set_parent(database.instance().FullName());
  request.set_backup_id(backup_id);
  request.mutable_backup()->set_database(database.FullName());
  *request.mutable_backup()->mutable_expire_time() =
      expire_time.get<google::protobuf::Timestamp>().value();
  *request.mutable_backup()->mutable_version_time() =
      version_time.get<google::protobuf::Timestamp>().value();
  request.mutable_encryption_config()->set_encryption_type(
      google::spanner::admin::database::v1::CreateBackupEncryptionConfig::
          CUSTOMER_MANAGED_ENCRYPTION);
  request.mutable_encryption_config()->set_kms_key_name(
      encryption_key.FullName());
  auto backup = client.CreateBackup(request).get();
  if (!backup) throw std::move(backup).status();
  std::cout
      << "Backup " << backup->name() << " of " << backup->database()
      << " of size " << backup->size_bytes() << " bytes as of "
      << google::cloud::spanner::MakeTimestamp(backup->version_time()).value()
      << " was created at "
      << google::cloud::spanner::MakeTimestamp(backup->create_time()).value()
      << " using encryption key " << encryption_key.FullName() << ".\n";
}

Para crear una copia de seguridad con CMEK en una configuración de instancia multirregional, sigue estos pasos:

void CreateBackupWithMRCMEK(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    BackupIdentifier dst, std::string const& database_id,
    google::cloud::spanner::Timestamp expire_time,
    google::cloud::spanner::Timestamp version_time,
    std::vector<google::cloud::KmsKeyName> const& encryption_keys) {
  google::cloud::spanner::Database database(dst.project_id, dst.instance_id,
                                            database_id);
  google::spanner::admin::database::v1::CreateBackupRequest request;
  request.set_parent(database.instance().FullName());
  request.set_backup_id(dst.backup_id);
  request.mutable_backup()->set_database(database.FullName());
  *request.mutable_backup()->mutable_expire_time() =
      expire_time.get<google::protobuf::Timestamp>().value();
  *request.mutable_backup()->mutable_version_time() =
      version_time.get<google::protobuf::Timestamp>().value();
  request.mutable_encryption_config()->set_encryption_type(
      google::spanner::admin::database::v1::CreateBackupEncryptionConfig::
          CUSTOMER_MANAGED_ENCRYPTION);
  for (google::cloud::KmsKeyName const& encryption_key : encryption_keys) {
    request.mutable_encryption_config()->add_kms_key_names(
        encryption_key.FullName());
  }
  auto backup = client.CreateBackup(request).get();
  if (!backup) throw std::move(backup).status();
  std::cout
      << "Backup " << backup->name() << " of " << backup->database()
      << " of size " << backup->size_bytes() << " bytes as of "
      << google::cloud::spanner::MakeTimestamp(backup->version_time()).value()
      << " was created at "
      << google::cloud::spanner::MakeTimestamp(backup->create_time()).value();
  PrintKmsKeys(encryption_keys);
}

Go

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, sigue estos pasos:


import (
	"context"
	"fmt"
	"io"
	"regexp"
	"time"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
	pbt "github.com/golang/protobuf/ptypes/timestamp"
)

func createBackupWithCustomerManagedEncryptionKey(ctx context.Context, w io.Writer, db, backupID, kmsKeyName string) error {
	// db = `projects/<project>/instances/<instance-id>/database/<database-id>`
	// backupID = `my-backup-id`
	// kmsKeyName = `projects/<project>/locations/<location>/keyRings/<key_ring>/cryptoKeys/<kms_key_name>`
	matches := regexp.MustCompile("^(.+)/databases/(.+)$").FindStringSubmatch(db)
	if matches == nil || len(matches) != 3 {
		return fmt.Errorf("createBackupWithCustomerManagedEncryptionKey: invalid database id %q", db)
	}
	instanceName := matches[1]

	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return fmt.Errorf("createBackupWithCustomerManagedEncryptionKey.NewDatabaseAdminClient: %w", err)
	}
	defer adminClient.Close()

	expireTime := time.Now().AddDate(0, 0, 14)
	// Create a backup for a database using a Customer Managed Encryption Key
	req := adminpb.CreateBackupRequest{
		Parent:   instanceName,
		BackupId: backupID,
		Backup: &adminpb.Backup{
			Database:   db,
			ExpireTime: &pbt.Timestamp{Seconds: expireTime.Unix(), Nanos: int32(expireTime.Nanosecond())},
		},
		EncryptionConfig: &adminpb.CreateBackupEncryptionConfig{
			KmsKeyName:     kmsKeyName,
			EncryptionType: adminpb.CreateBackupEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION,
		},
	}
	op, err := adminClient.CreateBackup(ctx, &req)
	if err != nil {
		return fmt.Errorf("createBackupWithCustomerManagedEncryptionKey.CreateBackup: %w", err)
	}
	// Wait for backup operation to complete.
	backup, err := op.Wait(ctx)
	if err != nil {
		return fmt.Errorf("createBackupWithCustomerManagedEncryptionKey.Wait: %w", err)
	}

	// Get the name, create time, backup size and encryption key from the backup.
	backupCreateTime := time.Unix(backup.CreateTime.Seconds, int64(backup.CreateTime.Nanos))
	fmt.Fprintf(w,
		"Backup %s of size %d bytes was created at %s using encryption key %s\n",
		backup.Name,
		backup.SizeBytes,
		backupCreateTime.Format(time.RFC3339),
		kmsKeyName)
	return nil
}

Para crear una copia de seguridad con CMEK en una configuración de instancia multirregional, sigue estos pasos:


import (
	"context"
	"fmt"
	"io"
	"time"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
	pbt "github.com/golang/protobuf/ptypes/timestamp"
)

// createBackupWithCustomerManagedMultiRegionEncryptionKey creates a backup for a database using a Customer Managed Multi-Region Encryption Key.
func createBackupWithCustomerManagedMultiRegionEncryptionKey(ctx context.Context, w io.Writer, projectID, instanceID, databaseID, backupID string, kmsKeyNames []string) error {
	// projectID = `my-project`
	// instanceID = `my-instance`
	// databaseID = `my-database`
	// backupID = `my-backup-id`
	// kmsKeyNames := []string{"projects/my-project/locations/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	//	 "projects/my-project/locations/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	//	 "projects/my-project/locations/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	// }

	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return fmt.Errorf("createBackupWithCustomerManagedMultiRegionEncryptionKey.NewDatabaseAdminClient: %w", err)
	}
	defer adminClient.Close()

	expireTime := time.Now().AddDate(0, 0, 14)
	// Create a backup for a database using a Customer Managed Encryption Key
	req := adminpb.CreateBackupRequest{
		Parent:   fmt.Sprintf("projects/%s/instances/%s", projectID, instanceID),
		BackupId: backupID,
		Backup: &adminpb.Backup{
			Database:   fmt.Sprintf("projects/%s/instances/%s/databases/%s", projectID, instanceID, databaseID),
			ExpireTime: &pbt.Timestamp{Seconds: expireTime.Unix(), Nanos: int32(expireTime.Nanosecond())},
		},
		EncryptionConfig: &adminpb.CreateBackupEncryptionConfig{
			KmsKeyNames:    kmsKeyNames,
			EncryptionType: adminpb.CreateBackupEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION,
		},
	}
	op, err := adminClient.CreateBackup(ctx, &req)
	if err != nil {
		return fmt.Errorf("createBackupWithCustomerManagedMultiRegionEncryptionKey.CreateBackup: %w", err)
	}
	// Wait for backup operation to complete.
	backup, err := op.Wait(ctx)
	if err != nil {
		return fmt.Errorf("createBackupWithCustomerManagedMultiRegionEncryptionKey.Wait: %w", err)
	}

	// Get the name, create time, backup size and encryption key from the backup.
	backupCreateTime := time.Unix(backup.CreateTime.Seconds, int64(backup.CreateTime.Nanos))
	fmt.Fprintf(w,
		"Backup %s of size %d bytes was created at %s using multi-region encryption keys %q\n",
		backup.Name,
		backup.SizeBytes,
		backupCreateTime.Format(time.RFC3339),
		kmsKeyNames)
	return nil
}

Java

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, sigue estos pasos:


import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.protobuf.Timestamp;
import com.google.spanner.admin.database.v1.Backup;
import com.google.spanner.admin.database.v1.BackupName;
import com.google.spanner.admin.database.v1.CreateBackupEncryptionConfig;
import com.google.spanner.admin.database.v1.CreateBackupEncryptionConfig.EncryptionType;
import com.google.spanner.admin.database.v1.CreateBackupRequest;
import com.google.spanner.admin.database.v1.DatabaseName;
import com.google.spanner.admin.database.v1.InstanceName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.OffsetDateTime;

public class CreateBackupWithEncryptionKey {

  static void createBackupWithEncryptionKey() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String backupId = "my-backup";
    String kmsKeyName =
        "projects/" + projectId + "/locations/<location>/keyRings/<keyRing>/cryptoKeys/<keyId>";

    try (Spanner spanner =
        SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
      createBackupWithEncryptionKey(
          adminClient,
          projectId,
          instanceId,
          databaseId,
          backupId,
          kmsKeyName);
    }
  }

  static Void createBackupWithEncryptionKey(DatabaseAdminClient adminClient,
      String projectId, String instanceId, String databaseId, String backupId, String kmsKeyName) {
    // Set expire time to 14 days from now.
    final Timestamp expireTime =
        Timestamp.newBuilder().setSeconds(TimeUnit.MILLISECONDS.toSeconds((
            System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14)))).build();
    final BackupName backupName = BackupName.of(projectId, instanceId, backupId);
    Backup backup = Backup.newBuilder()
        .setName(backupName.toString())
        .setDatabase(DatabaseName.of(projectId, instanceId, databaseId).toString())
        .setExpireTime(expireTime).build();

    final CreateBackupRequest request =
        CreateBackupRequest.newBuilder()
            .setParent(InstanceName.of(projectId, instanceId).toString())
            .setBackupId(backupId)
            .setBackup(backup)
            .setEncryptionConfig(
                CreateBackupEncryptionConfig.newBuilder()
                    .setEncryptionType(EncryptionType.CUSTOMER_MANAGED_ENCRYPTION)
                    .setKmsKeyName(kmsKeyName).build()).build();
    try {
      System.out.println("Waiting for operation to complete...");
      backup = adminClient.createBackupAsync(request).get(1200, TimeUnit.SECONDS);
    } catch (ExecutionException e) {
      // If the operation failed during execution, expose the cause.
      throw SpannerExceptionFactory.asSpannerException(e.getCause());
    } catch (InterruptedException e) {
      // Throw when a thread is waiting, sleeping, or otherwise occupied,
      // and the thread is interrupted, either before or during the activity.
      throw SpannerExceptionFactory.propagateInterrupt(e);
    } catch (TimeoutException e) {
      // If the operation timed out propagates the timeout
      throw SpannerExceptionFactory.propagateTimeout(e);
    }
    System.out.printf(
        "Backup %s of size %d bytes was created at %s using encryption key %s%n",
        backup.getName(),
        backup.getSizeBytes(),
        LocalDateTime.ofEpochSecond(
            backup.getCreateTime().getSeconds(),
            backup.getCreateTime().getNanos(),
            OffsetDateTime.now().getOffset()),
        kmsKeyName
    );

    return null;
  }
}

Para crear una copia de seguridad con CMEK en una configuración de instancia multirregional, sigue estos pasos:


import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
import com.google.protobuf.Timestamp;
import com.google.spanner.admin.database.v1.Backup;
import com.google.spanner.admin.database.v1.BackupName;
import com.google.spanner.admin.database.v1.CreateBackupEncryptionConfig;
import com.google.spanner.admin.database.v1.CreateBackupEncryptionConfig.EncryptionType;
import com.google.spanner.admin.database.v1.CreateBackupRequest;
import com.google.spanner.admin.database.v1.DatabaseName;
import com.google.spanner.admin.database.v1.InstanceName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.OffsetDateTime;

public class CreateBackupWithMultiRegionEncryptionKey {

  static void createBackupWithMultiRegionEncryptionKey() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String backupId = "my-backup";
    String[] kmsKeyNames =
        new String[] {
          "projects/" + projectId + "/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
          "projects/" + projectId + "/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
          "projects/" + projectId + "/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>"
        };

    try (Spanner spanner =
            SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
      createBackupWithMultiRegionEncryptionKey(
          adminClient, projectId, instanceId, databaseId, backupId, kmsKeyNames);
    }
  }

  static Void createBackupWithMultiRegionEncryptionKey(
      DatabaseAdminClient adminClient,
      String projectId,
      String instanceId,
      String databaseId,
      String backupId,
      String[] kmsKeyNames) {
    // Set expire time to 14 days from now.
    final Timestamp expireTime =
        Timestamp.newBuilder()
            .setSeconds(
                TimeUnit.MILLISECONDS.toSeconds(
                    (System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14))))
            .build();
    final BackupName backupName = BackupName.of(projectId, instanceId, backupId);
    Backup backup =
        Backup.newBuilder()
            .setName(backupName.toString())
            .setDatabase(DatabaseName.of(projectId, instanceId, databaseId).toString())
            .setExpireTime(expireTime)
            .build();

    final CreateBackupRequest request =
        CreateBackupRequest.newBuilder()
            .setParent(InstanceName.of(projectId, instanceId).toString())
            .setBackupId(backupId)
            .setBackup(backup)
            .setEncryptionConfig(
                CreateBackupEncryptionConfig.newBuilder()
                    .setEncryptionType(EncryptionType.CUSTOMER_MANAGED_ENCRYPTION)
                    .addAllKmsKeyNames(ImmutableList.copyOf(kmsKeyNames))
                    .build())
            .build();
    try {
      System.out.println("Waiting for operation to complete...");
      backup = adminClient.createBackupAsync(request).get(1200, TimeUnit.SECONDS);
    } catch (ExecutionException e) {
      // If the operation failed during execution, expose the cause.
      throw SpannerExceptionFactory.asSpannerException(e.getCause());
    } catch (InterruptedException e) {
      // Throw when a thread is waiting, sleeping, or otherwise occupied,
      // and the thread is interrupted, either before or during the activity.
      throw SpannerExceptionFactory.propagateInterrupt(e);
    } catch (TimeoutException e) {
      // If the operation timed out propagates the timeout
      throw SpannerExceptionFactory.propagateTimeout(e);
    }
    System.out.printf(
        "Backup %s of size %d bytes was created at %s using encryption keys %s%n",
        backup.getName(),
        backup.getSizeBytes(),
        LocalDateTime.ofEpochSecond(
            backup.getCreateTime().getSeconds(),
            backup.getCreateTime().getNanos(),
            OffsetDateTime.now().getOffset()),
        ImmutableList.copyOf(kmsKeyNames));

    return null;
  }
}

Node.js

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, sigue estos pasos:


// Imports the Google Cloud client library
const {Spanner, protos} = require('@google-cloud/spanner');
const {PreciseDate} = require('@google-cloud/precise-date');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const backupId = 'my-backup';
// const keyName =
//   'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key';

// Creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner Database Admin Client object
const databaseAdminClient = spanner.getDatabaseAdminClient();

// Creates a new backup of the database
try {
  console.log(
    `Creating backup of database ${databaseAdminClient.databasePath(
      projectId,
      instanceId,
      databaseId,
    )}.`,
  );

  // Expire backup 14 days in the future
  const expireTime = Date.now() + 1000 * 60 * 60 * 24 * 14;

  // Create a backup of the state of the database at the current time.
  const [operation] = await databaseAdminClient.createBackup({
    parent: databaseAdminClient.instancePath(projectId, instanceId),
    backupId: backupId,
    backup: (protos.google.spanner.admin.database.v1.Backup = {
      database: databaseAdminClient.databasePath(
        projectId,
        instanceId,
        databaseId,
      ),
      expireTime: Spanner.timestamp(expireTime).toStruct(),
      name: databaseAdminClient.backupPath(projectId, instanceId, backupId),
    }),
    encryptionConfig: {
      encryptionType: 'CUSTOMER_MANAGED_ENCRYPTION',
      kmsKeyName: keyName,
    },
  });

  console.log(
    `Waiting for backup ${databaseAdminClient.backupPath(
      projectId,
      instanceId,
      backupId,
    )} to complete...`,
  );
  await operation.promise();

  // Verify backup is ready
  const [backupInfo] = await databaseAdminClient.getBackup({
    name: databaseAdminClient.backupPath(projectId, instanceId, backupId),
  });
  if (backupInfo.state === 'READY') {
    console.log(
      `Backup ${backupInfo.name} of size ` +
        `${backupInfo.sizeBytes} bytes was created at ` +
        `${new PreciseDate(backupInfo.createTime).toISOString()} ` +
        `using encryption key ${backupInfo.encryptionInfo.kmsKeyVersion}`,
    );
  } else {
    console.error('ERROR: Backup is not ready.');
  }
} catch (err) {
  console.error('ERROR:', err);
} finally {
  // Close the spanner client when finished.
  // The databaseAdminClient does not require explicit closure. The closure of the Spanner client will automatically close the databaseAdminClient.
  spanner.close();
}

Para crear una copia de seguridad con CMEK en una configuración de instancia multirregional, sigue estos pasos:

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const backupId = 'my-backup';
// const kmsKeyNames =
//   'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key1,
//   'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key2';

// Imports the Google Cloud client library
const {Spanner, protos} = require('@google-cloud/spanner');
const {PreciseDate} = require('@google-cloud/precise-date');

// Creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner Database Admin Client object
const databaseAdminClient = spanner.getDatabaseAdminClient();
async function createBackupWithMultipleKmsKeys() {
  // Creates a new backup of the database
  try {
    console.log(
      `Creating backup of database ${databaseAdminClient.databasePath(
        projectId,
        instanceId,
        databaseId,
      )}.`,
    );

    // Expire backup 14 days in the future
    const expireTime = Date.now() + 1000 * 60 * 60 * 24 * 14;

    // Create a backup of the state of the database at the current time.
    const [operation] = await databaseAdminClient.createBackup({
      parent: databaseAdminClient.instancePath(projectId, instanceId),
      backupId: backupId,
      backup: (protos.google.spanner.admin.database.v1.Backup = {
        database: databaseAdminClient.databasePath(
          projectId,
          instanceId,
          databaseId,
        ),
        expireTime: Spanner.timestamp(expireTime).toStruct(),
        name: databaseAdminClient.backupPath(projectId, instanceId, backupId),
      }),
      encryptionConfig: {
        encryptionType: 'CUSTOMER_MANAGED_ENCRYPTION',
        kmsKeyNames: kmsKeyNames.split(','),
      },
    });

    console.log(
      `Waiting for backup ${databaseAdminClient.backupPath(
        projectId,
        instanceId,
        backupId,
      )} to complete...`,
    );
    await operation.promise();

    // Verify backup is ready
    const [backupInfo] = await databaseAdminClient.getBackup({
      name: databaseAdminClient.backupPath(projectId, instanceId, backupId),
    });

    const kmsKeyVersions = backupInfo.encryptionInformation
      .map(encryptionInfo => encryptionInfo.kmsKeyVersion)
      .join(', ');

    if (backupInfo.state === 'READY') {
      console.log(
        `Backup ${backupInfo.name} of size ` +
          `${backupInfo.sizeBytes} bytes was created at ` +
          `${new PreciseDate(backupInfo.createTime).toISOString()} ` +
          `using encryption key ${kmsKeyVersions}`,
      );
    } else {
      console.error('ERROR: Backup is not ready.');
    }
  } catch (err) {
    console.error('ERROR:', err);
  } finally {
    // Close the spanner client when finished.
    // The databaseAdminClient does not require explicit closure. The closure of the Spanner client will automatically close the databaseAdminClient.
    spanner.close();
  }
}
createBackupWithMultipleKmsKeys();

PHP

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, sigue estos pasos:


use Google\Cloud\Spanner\Admin\Database\V1\Backup;
use \Google\Cloud\Spanner\Admin\Database\V1\Backup\State;
use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\CreateBackupEncryptionConfig;
use Google\Cloud\Spanner\Admin\Database\V1\CreateBackupRequest;
use Google\Cloud\Spanner\Admin\Database\V1\GetBackupRequest;
use Google\Protobuf\Timestamp;

/**
 * Create an encrypted backup.
 * Example:
 * ```
 * create_backup_with_encryption_key($projectId, $instanceId, $databaseId, $backupId, $kmsKeyName);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 * @param string $backupId The Spanner backup ID.
 * @param string $kmsKeyName The KMS key used for encryption.
 */
function create_backup_with_encryption_key(
    string $projectId,
    string $instanceId,
    string $databaseId,
    string $backupId,
    string $kmsKeyName
): void {
    $databaseAdminClient = new DatabaseAdminClient();
    $instanceFullName = DatabaseAdminClient::instanceName($projectId, $instanceId);
    $databaseFullName = DatabaseAdminClient::databaseName($projectId, $instanceId, $databaseId);
    $expireTime = new Timestamp();
    $expir>eTime-setSeconds((new \DateTime('+14 da>ys'))-getTimestamp());
    $request = new CreateBackupRequest([
        'par>ent' = $instanceFullName,
        'backup>_id' = $backupId,
        'encryption_con>fig' = new CreateBackupEncryptionConfig([
            'kms_key_n>ame' = $kmsKeyName,
            'encryption_t>ype' = CreateBackupEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION
        ]),
        'bac>kup' = new Backup([
            'datab>ase' = $databaseFullName,
            'expire_t>ime' = $expireTime
        ])
    ]);

    $operation = $databaseAdminC>lient-createBackup($request);

    print('Waiting for operation to complete...' . PHP_EOL);
    $oper>ation-pollUntilComplete();

    $request = new GetBackupRequest();
    $re>quest-setName($databaseAdminC>lient-backupName($projectId, $instanceId, $backupId));
    $info = $databaseAdminC>lient-getBackup($request);
    if (State::name(>$info-getState()) == 'READY') {
        printf(
            'Backup %s of size %d bytes was created at %d using encryption key %s' . PHP_EOL,
            basename(>$info-getName()),
            >$info-getSizeBytes(),
            >$info-getCreateT>ime()-getSeconds(),
            >$info-getEncryptionI>nfo()-getKmsKeyVersion()
        );
    } else {
        print('Backup is not ready!' . PHP_EOL);
    }
}

Para crear una copia de seguridad con CMEK en una configuración de instancia multirregional, sigue estos pasos:


use Google\Cloud\Spanner\Admin\Database\V1\Backup;
use \Google\Cloud\Spanner\Admin\Database\V1\Backup\State;
use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\CreateBackupEncryptionConfig;
use Google\Cloud\Spanner\Admin\Database\V1\CreateBackupRequest;
use Google\Cloud\Spanner\Admin\Database\V1\GetBackupRequest;
use Google\Protobuf\Timestamp;

/**
 * Create a CMEK backup.
 * Example:
 * ```
 * create_backup_with_mr_cmek($projectId, $instanceId, $databaseId, $backupId, $kmsKeyNames);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 * @param string $backupId The Spanner backup ID.
 * @param string[] $kmsKeyNames The KMS keys used for encryption.
 */
function create_backup_with_mr_cmek(
    string $projectId,
    string $instanceId,
    string $databaseId,
    string $backupId,
    array $kmsKeyNames
): void {
    $databaseAdminClient = new DatabaseAdminClient();
    $instanceFullName = DatabaseAdminClient::instanceName($projectId, $instanceId);
    $databaseFullName = DatabaseAdminClient::databaseName($projectId, $instanceId, $databaseId);
    $expireTime = new Timestamp();
    $expir>eTime-setSeconds((new \DateTime('+14 da>ys'))-getTimestamp());
    $request = new CreateBackupRequest([
        'par>ent' = $instanceFullName,
        'backup>_id' = $backupId,
        'encryption_con>fig' = new CreateBackupEncryptionConfig([
            'kms_key_na>mes' = $kmsKeyNames,
            'encryption_t>ype' = CreateBackupEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION
        ]),
        'bac>kup' = new Backup([
            'datab>ase' = $databaseFullName,
            'expire_t>ime' = $expireTime
        ])
    ]);

    $operation = $databaseAdminC>lient-createBackup($request);

    print('Waiting for operation to complete...' . PHP_EOL);
    $oper>ation-pollUntilComplete();

    $request = new GetBackupRequest();
    $re>quest-setName($databaseAdminC>lient-backupName($projectId, $instanceId, $backupId));
    $info = $databaseAdminC>lient-getBackup($request);
    if (State::name(>$info-getState()) == 'READY') {
        $kmsKeyVersions = [];
        foreach (>$info-getEncryptionInformation() as $encryptionInfo) {
            $kmsKeyVersions[] = $encryptio>nInfo-getKmsKeyVersion();
        }
        printf(
            'Backup %s of size %d bytes was created at %d using encryption keys %s' . PHP_EOL,
            basename(>$info-getName()),
            >$info-getSizeBytes(),
            >$info-getCreateT>ime()-getSeconds(),
            print_r($kmsKeyVersions, true)
        );
    } else {
        print('Backup is not ready!' . PHP_EOL);
    }
}

Python

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, sigue estos pasos:

def create_backup_with_encryption_key(
    instance_id, database_id, backup_id, kms_key_name
):
    """Creates a backup for a database using a Customer Managed Encryption Key (CMEK)."""

    from google.cloud.spanner_admin_database_v1 import CreateBackupEncryptionConfig
    from google.cloud.spanner_admin_database_v1.types import backup as backup_pb

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    # Create a backup
    expire_time = datetime.utcnow() + timedelta(days=14)
    encryption_config = {
        "encryption_type": CreateBackupEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION,
        "kms_key_name": kms_key_name,
    }
    request = backup_pb.CreateBackupRequest(
        parent=database_admin_api.instance_path(spanner_client.project, instance_id),
        backup_id=backup_id,
        backup=backup_pb.Backup(
            database=database_admin_api.database_path(
                spanner_client.project, instance_id, database_id
            ),
            expire_time=expire_time,
        ),
        encryption_config=encryption_config,
    )
    operation = database_admin_api.create_backup(request)

    # Wait for backup operation to complete.
    backup = operation.result(2100)

    # Verify that the backup is ready.
    assert backup.state == backup_pb.Backup.State.READY

    # Get the name, create time, backup size and encryption key.
    print(
        "Backup {} of size {} bytes was created at {} using encryption key {}".format(
            backup.name, backup.size_bytes, backup.create_time, kms_key_name
        )
    )

Para crear una copia de seguridad con CMEK en una configuración de instancia multirregional, sigue estos pasos:

def create_backup_with_multiple_kms_keys(
    instance_id, database_id, backup_id, kms_key_names
):
    """Creates a backup for a database using multiple KMS keys(CMEK)."""

    from google.cloud.spanner_admin_database_v1 import CreateBackupEncryptionConfig
    from google.cloud.spanner_admin_database_v1.types import backup as backup_pb

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    # Create a backup
    expire_time = datetime.utcnow() + timedelta(days=14)
    encryption_config = {
        "encryption_type": CreateBackupEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION,
        "kms_key_names": kms_key_names,
    }
    request = backup_pb.CreateBackupRequest(
        parent=database_admin_api.instance_path(spanner_client.project, instance_id),
        backup_id=backup_id,
        backup=backup_pb.Backup(
            database=database_admin_api.database_path(
                spanner_client.project, instance_id, database_id
            ),
            expire_time=expire_time,
        ),
        encryption_config=encryption_config,
    )
    operation = database_admin_api.create_backup(request)

    # Wait for backup operation to complete.
    backup = operation.result(2100)

    # Verify that the backup is ready.
    assert backup.state == backup_pb.Backup.State.READY

    # Get the name, create time, backup size and encryption key.
    print(
        "Backup {} of size {} bytes was created at {} using encryption key {}".format(
            backup.name, backup.size_bytes, backup.create_time, kms_key_names
        )
    )

Ruby

Para crear una copia de seguridad con CMEK en una configuración de instancia regional, sigue estos pasos:

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
# backup_id = "Your Spanner backup ID"
# kms_key_name = "Your backup encryption database KMS key"

require "google/cloud/spanner"
require "google/cloud/spanner/admin/database"

database_admin_client = Google::Cloud::Spanner::Admin::Database.database_admin

instance_path = database_admin_client.instance_path project: project_id, instance: instance_id
db_path = database_admin_client.database_path project: project_id,
                                              instance: instance_id,
                                              database: database_id
backup_path = database_admin_client.backup_path project: project_id,
                                                instance: instance_id,
                                                backup: backup_id
expire_time = Time.now + (14 * 24 * 3600) # 14 days from now
encryption_config = {
  encryption_type: :CUSTOMER_MANAGED_ENCRYPTION,
  kms_key_name:    kms_key_name
}

job = database_admin_client.create_backup parent: instance_path,
                                          backup_id: backup_id,
                                          backup: {
                                            database: db_path,
                                              expire_time: expire_time
                                          },
                                          encryption_config: encryption_config

puts "Backup operation in progress"

job.wait_until_done!

backup = database_admin_client.get_backup name: backup_path
puts "Backup #{backup_id} of size #{backup.size_bytes} bytes was created at #{backup.create_time} using encryption key #{kms_key_name}"

Para crear una copia de seguridad con CMEK en una configuración de instancia multirregional, sigue estos pasos:

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
# backup_id = "Your Spanner backup ID"
# kms_key_names = ["key1", "key2", "key3"]

require "google/cloud/spanner"
require "google/cloud/spanner/admin/database"

database_admin_client = Google::Cloud::Spanner::Admin::Database.database_admin

instance_path = database_admin_client.instance_path(
  project: project_id, instance: instance_id
)
db_path = database_admin_client.database_path project: project_id,
                                              instance: instance_id,
                                              database: database_id
backup_path = database_admin_client.backup_path project: project_id,
                                                instance: instance_id,
                                                backup: backup_id
expire_time = Time.now + (14 * 24 * 3600) # 14 days from now
encryption_config = {
  encryption_type: :CUSTOMER_MANAGED_ENCRYPTION,
  kms_key_names:    kms_key_names
}

job = database_admin_client.create_backup parent: instance_path,
                                          backup_id: backup_id,
                                          backup: {
                                            database: db_path,
                                            expire_time: expire_time
                                          },
                                          encryption_config: encryption_config

puts "Backup operation in progress"

job.wait_until_done!

backup = database_admin_client.get_backup name: backup_path
puts "Backup #{backup_id} of size #{backup.size_bytes} bytes was created " \
     "at #{backup.create_time} using encryption key #{kms_key_names}"

Copiar una copia de seguridad

Puedes copiar una copia de seguridad de tu base de datos de Spanner de una instancia a otra en otra región u otro proyecto. De forma predeterminada, una copia de seguridad utiliza la misma configuración de cifrado (gestionada por Google o por el cliente) que la copia de seguridad de origen. Puedes anular este comportamiento especificando una configuración de cifrado diferente al copiar la copia de seguridad. Si quieres que la copia de seguridad se cifre con CMEK al copiarla entre regiones, especifica las claves de Cloud KMS correspondientes a las regiones de destino.

Consola

Usa la consola para copiar una copia de seguridad en una configuración de instancia regional.

  1. En la consola, ve a la página Instancias. Google Cloud

    Ir a instancias de Spanner

  2. Haga clic en el nombre de la instancia que contiene la base de datos de la que quiere crear una copia de seguridad.

  3. Haz clic en la base de datos.

  4. En el panel de navegación, haz clic en Copia de seguridad o restauración.

  5. En la tabla Copias de seguridad, seleccione Acciones en la copia de seguridad y haga clic en Copiar.

  6. Rellena el formulario. Para ello, elige una instancia de destino, proporciona un nombre y selecciona una fecha de vencimiento para la copia de seguridad.

  7. Opcional: Si quieres usar una configuración de cifrado diferente para tu copia de seguridad, haz clic en Mostrar opciones de cifrado.

    a. Selecciona Clave de Cloud KMS.

    a. Seleccione una clave de la lista desplegable.

    La lista de claves se limita al proyecto Google Cloud actual. Para usar una clave de otro proyecto, crea la base de datos con la CLI de gcloud en lugar de con la consola. Google Cloud Google Cloud

  8. Haz clic en Copiar.

gcloud

Para copiar una copia de seguridad con una nueva configuración de cifrado en otra instancia del mismo proyecto, ejecuta el siguiente comando gcloud spanner backups copy:

gcloud spanner backups copy --async \
    --source-instance=INSTANCE_ID \
    --source-backup=SOURCE_BACKUP_NAME \
    --destination-instance=DESTINATION_INSTANCE_ID \
    --destination-backup=DESTINATION_BACKUP_NAME \
    --expiration-date=EXPIRATION_DATE \
    --encryption-type=CUSTOMER_MANAGED_ENCRYPTION \
    --kms-keys=KMS_KEY_1[, KMS_KEY_2 ... ]

Para copiar una copia de seguridad con una nueva configuración de cifrado en otra instancia de otro proyecto, ejecuta el siguiente comando gcloud spanner backups copy:

gcloud spanner backups copy --async \
    --source-backup=SOURCE_BACKUP_NAME \
    --destination-backup=DESTINATION_BACKUP_NAME \
    --encryption-type=CUSTOMER_MANAGED_ENCRYPTION \
    --kms-keys=KMS_KEY_1[, KMS_KEY_2 ... ]

Para verificar que la copia de seguridad copiada está cifrada con CMEK, sigue estos pasos:

gcloud spanner backups describe BACKUP \
    --project=SPANNER_PROJECT_ID \
    --instance=INSTANCE_ID

Bibliotecas de cliente

C#

Para copiar una copia de seguridad con CMEK habilitada en una configuración de instancia multirregional, sigue estos pasos:


using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using Google.Protobuf.WellKnownTypes;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class CopyBackupWithMultiRegionEncryptionAsyncSample
{
    public async Task<Backup> CopyBackupWithMultiRegionEncryptionAsync(
        string sourceProjectId, string sourceInstanceId, string sourceBackupId,
        string targetProjectId, string targetInstanceId, string targetBackupId,
        DateTimeOffset expireTime, IEnumerable<CryptoKeyName> kmsKeyNames)
    {
        DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();

        var request = new CopyBackupRequest
        {
            SourceBackupAsBackupName = new BackupName(sourceProjectId, sourceInstanceId, sourceBackupId),
            ParentAsInstanceName = new InstanceName(targetProjectId, targetInstanceId),
            BackupId = targetBackupId,
            ExpireTime = Timestamp.FromDateTimeOffset(expireTime),
            EncryptionConfig = new CopyBackupEncryptionConfig
            {
                EncryptionType = CopyBackupEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,
                KmsKeyNamesAsCryptoKeyNames = { kmsKeyNames },
            }
        };

        // Execute the CopyBackup request.
        var operation = await databaseAdminClient.CopyBackupAsync(request);

        Console.WriteLine("Waiting for the operation to finish.");

        // Poll until the returned long-running operation is complete.
        var completedResponse = await operation.PollUntilCompletedAsync();

        if (completedResponse.IsFaulted)
        {
            Console.WriteLine($"Error while copying backup: {completedResponse.Exception}");
            throw completedResponse.Exception;
        }

        Backup backup = completedResponse.Result;

        Console.WriteLine($"Backup copied successfully.");
        Console.WriteLine($"Backup with Id {sourceBackupId} has been copied from {sourceProjectId}/{sourceInstanceId} to {targetProjectId}/{targetInstanceId} Backup {targetBackupId}");
        Console.WriteLine($"Backup {backup.Name} of size {backup.SizeBytes} bytes was created with encryption keys {string.Join(", ", kmsKeyNames)} at {backup.CreateTime} from {backup.Database} and is in state {backup.State} and has version time {backup.VersionTime}");

        return backup;
    }
}

C++

Para copiar una copia de seguridad con CMEK habilitada en una configuración de instancia multirregional, sigue estos pasos:

struct BackupIdentifier {
  std::string project_id;
  std::string instance_id;
  std::string backup_id;
};

void PrintKmsKeys(
    std::vector<google::cloud::KmsKeyName> const& encryption_keys) {
  std::cout << " using encryption keys ";
  for (std::size_t i = 0; i < encryption_keys.size(); ++i) {
    std::cout << encryption_keys[i].FullName();
    if (i != encryption_keys.size() - 1) {
      std::cout << ", ";
    }
  }
  std::cout << ".\n";
}

void CopyBackupWithMRCMEK(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    BackupIdentifier const& src, BackupIdentifier const& dst,
    google::cloud::spanner::Timestamp expire_time,
    std::vector<google::cloud::KmsKeyName> const& encryption_keys) {
  google::cloud::spanner::Backup source(
      google::cloud::spanner::Instance(src.project_id, src.instance_id),
      src.backup_id);
  google::cloud::spanner::Instance dst_in(dst.project_id, dst.instance_id);
  google::spanner::admin::database::v1::CopyBackupRequest request;
  request.set_backup_id(dst.backup_id);
  request.set_parent(dst_in.FullName());
  request.set_source_backup(source.FullName());
  *request.mutable_expire_time() =
      expire_time.get<google::protobuf::Timestamp>().value();
  request.mutable_encryption_config()->set_encryption_type(
      google::spanner::admin::database::v1::CopyBackupEncryptionConfig::
          CUSTOMER_MANAGED_ENCRYPTION);
  for (google::cloud::KmsKeyName const& encryption_key : encryption_keys) {
    request.mutable_encryption_config()->add_kms_key_names(
        encryption_key.FullName());
  }
  auto copy_backup = client.CopyBackup(request).get();
  if (!copy_backup) throw std::move(copy_backup).status();
  std::cout << "Copy Backup " << copy_backup->name()  //
            << " of " << source.FullName()            //
            << " of size " << copy_backup->size_bytes() << " bytes as of "
            << google::cloud::spanner::MakeTimestamp(
                   copy_backup->version_time())
                   .value()
            << " was created at "
            << google::cloud::spanner::MakeTimestamp(copy_backup->create_time())
                   .value();
  PrintKmsKeys(encryption_keys);
}

Go

Para copiar una copia de seguridad con CMEK habilitada en una configuración de instancia multirregional, sigue estos pasos:


import (
	"context"
	"fmt"
	"io"
	"time"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
	pbt "github.com/golang/protobuf/ptypes/timestamp"
)

// copyBackupWithMultiRegionEncryptionKey copies an existing backup to a given instance in same or different region, or in same or different project with multiple encryption keys.
func copyBackupWithMultiRegionEncryptionKey(w io.Writer, instancePath string, copyBackupId string, sourceBackupPath string, kmsKeyNames []string) error {
	// instancePath := "projects/my-project/instances/my-instance"
	// copyBackupId := "my-copy-backup"
	// sourceBackupPath := "projects/my-project/instances/my-instance/backups/my-source-backup"
	// kmsKeyNames := []string{"projects/my-project/locations/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	//	 "projects/my-project/locations/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	//	 "projects/my-project/locations/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	// }

	// Add timeout to context.
	ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
	defer cancel()

	// Instantiate database admin client.
	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return fmt.Errorf("database.NewDatabaseAdminClient: %w", err)
	}
	defer adminClient.Close()

	expireTime := time.Now().AddDate(0, 0, 14)

	// Instantiate the request for performing copy backup operation.
	copyBackupReq := adminpb.CopyBackupRequest{
		Parent:       instancePath,
		BackupId:     copyBackupId,
		SourceBackup: sourceBackupPath,
		ExpireTime:   &pbt.Timestamp{Seconds: expireTime.Unix(), Nanos: int32(expireTime.Nanosecond())},
		EncryptionConfig: &adminpb.CopyBackupEncryptionConfig{
			EncryptionType: adminpb.CopyBackupEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION,
			KmsKeyNames:    kmsKeyNames,
		},
	}

	// Start copying the backup.
	copyBackupOp, err := adminClient.CopyBackup(ctx, &copyBackupReq)
	if err != nil {
		return fmt.Errorf("adminClient.CopyBackup: %w", err)
	}

	// Wait for copy backup operation to complete.
	fmt.Fprintf(w, "Waiting for backup copy %s/backups/%s to complete...\n", instancePath, copyBackupId)
	copyBackup, err := copyBackupOp.Wait(ctx)
	if err != nil {
		return fmt.Errorf("copyBackup.Wait: %w", err)
	}

	// Check if long-running copyBackup operation is completed.
	if !copyBackupOp.Done() {
		return fmt.Errorf("backup %v could not be copied to %v", sourceBackupPath, copyBackupId)
	}

	// Get the name, create time, version time and backup size.
	copyBackupCreateTime := time.Unix(copyBackup.CreateTime.Seconds, int64(copyBackup.CreateTime.Nanos))
	copyBackupVersionTime := time.Unix(copyBackup.VersionTime.Seconds, int64(copyBackup.VersionTime.Nanos))
	fmt.Fprintf(w,
		"Backup %s of size %d bytes was created at %s with version time %s using multi-region encryption keys\n",
		copyBackup.Name,
		copyBackup.SizeBytes,
		copyBackupCreateTime.Format(time.RFC3339),
		copyBackupVersionTime.Format(time.RFC3339))

	return nil
}

Java

Para copiar una copia de seguridad con CMEK habilitada en una configuración de instancia multirregional, sigue estos pasos:


import com.google.cloud.Timestamp;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.database.v1.Backup;
import com.google.spanner.admin.database.v1.BackupName;
import com.google.spanner.admin.database.v1.CopyBackupEncryptionConfig;
import com.google.spanner.admin.database.v1.CopyBackupEncryptionConfig.EncryptionType;
import com.google.spanner.admin.database.v1.CopyBackupRequest;
import com.google.spanner.admin.database.v1.InstanceName;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class CopyBackupWithMultiRegionEncryptionKey {

  static void copyBackupWithMultiRegionEncryptionKey() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String sourceBackupId = "my-backup";
    String destinationBackupId = "my-destination-backup";
    String[] kmsKeyNames =
        new String[] {
          "projects/" + projectId + "/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
          "projects/" + projectId + "/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
          "projects/" + projectId + "/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>"
        };

    try (Spanner spanner =
            SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
      copyBackupWithMultiRegionEncryptionKey(
          databaseAdminClient,
          projectId,
          instanceId,
          sourceBackupId,
          destinationBackupId,
          kmsKeyNames);
    }
  }

  static void copyBackupWithMultiRegionEncryptionKey(
      DatabaseAdminClient databaseAdminClient,
      String projectId,
      String instanceId,
      String sourceBackupId,
      String destinationBackupId,
      String[] kmsKeyNames) {

    Timestamp expireTime =
        Timestamp.ofTimeMicroseconds(
            TimeUnit.MICROSECONDS.convert(
                System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS));

    // Initiate the request which returns an OperationFuture.
    System.out.println("Copying backup [" + destinationBackupId + "]...");
    CopyBackupRequest request =
        CopyBackupRequest.newBuilder()
            .setParent(InstanceName.of(projectId, instanceId).toString())
            .setBackupId(destinationBackupId)
            .setSourceBackup(BackupName.of(projectId, instanceId, sourceBackupId).toString())
            .setExpireTime(expireTime.toProto())
            .setEncryptionConfig(
                CopyBackupEncryptionConfig.newBuilder()
                    .setEncryptionType(EncryptionType.CUSTOMER_MANAGED_ENCRYPTION)
                    .addAllKmsKeyNames(ImmutableList.copyOf(kmsKeyNames))
                    .build())
            .build();
    Backup destinationBackup;
    try {
      // Creates a copy of an existing backup.
      // Wait for the backup operation to complete.
      destinationBackup = databaseAdminClient.copyBackupAsync(request).get();
      System.out.println("Copied backup [" + destinationBackup.getName() + "]");
    } catch (ExecutionException e) {
      throw (SpannerException) e.getCause();
    } catch (InterruptedException e) {
      throw SpannerExceptionFactory.propagateInterrupt(e);
    }
    // Load the metadata of the new backup from the server.
    destinationBackup = databaseAdminClient.getBackup(destinationBackup.getName());
    System.out.println(
        String.format(
            "Backup %s of size %d bytes was copied at %s for version of database at %s",
            destinationBackup.getName(),
            destinationBackup.getSizeBytes(),
            OffsetDateTime.ofInstant(
                Instant.ofEpochSecond(
                    destinationBackup.getCreateTime().getSeconds(),
                    destinationBackup.getCreateTime().getNanos()),
                ZoneId.systemDefault()),
            OffsetDateTime.ofInstant(
                Instant.ofEpochSecond(
                    destinationBackup.getVersionTime().getSeconds(),
                    destinationBackup.getVersionTime().getNanos()),
                ZoneId.systemDefault())));
  }
}

Node.js

Para copiar una copia de seguridad con CMEK habilitada en una configuración de instancia multirregional, sigue estos pasos:

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const instanceId = 'my-instance';
// const backupId = 'my-backup',
// const sourceBackupPath = 'projects/my-project-id/instances/my-source-instance/backups/my-source-backup',
// const projectId = 'my-project-id';
// const kmsKeyNames =
//   'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key1,
//   projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key2';

// Imports the Google Cloud Spanner client library
const {Spanner} = require('@google-cloud/spanner');
const {PreciseDate} = require('@google-cloud/precise-date');

// Creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner Database Admin Client object
const databaseAdminClient = spanner.getDatabaseAdminClient();

async function spannerCopyBackupWithMultipleKmsKeys() {
  // Expire copy backup 14 days in the future
  const expireTime = Spanner.timestamp(
    Date.now() + 1000 * 60 * 60 * 24 * 14,
  ).toStruct();

  // Copy the source backup
  try {
    console.log(`Creating copy of the source backup ${sourceBackupPath}.`);
    const [operation] = await databaseAdminClient.copyBackup({
      parent: databaseAdminClient.instancePath(projectId, instanceId),
      sourceBackup: sourceBackupPath,
      backupId: backupId,
      expireTime: expireTime,
      kmsKeyNames: kmsKeyNames.split(','),
    });

    console.log(
      `Waiting for backup copy ${databaseAdminClient.backupPath(
        projectId,
        instanceId,
        backupId,
      )} to complete...`,
    );
    await operation.promise();

    // Verify the copy backup is ready
    const [copyBackup] = await databaseAdminClient.getBackup({
      name: databaseAdminClient.backupPath(projectId, instanceId, backupId),
    });

    if (copyBackup.state === 'READY') {
      console.log(
        `Backup copy ${copyBackup.name} of size ` +
          `${copyBackup.sizeBytes} bytes was created at ` +
          `${new PreciseDate(copyBackup.createTime).toISOString()} ` +
          'with version time ' +
          `${new PreciseDate(copyBackup.versionTime).toISOString()}`,
      );
    } else {
      console.error('ERROR: Copy of backup is not ready.');
    }
  } catch (err) {
    console.error('ERROR:', err);
  }
}
spannerCopyBackupWithMultipleKmsKeys();

PHP

Para copiar una copia de seguridad con CMEK habilitada en una configuración de instancia multirregional, sigue estos pasos:

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\CopyBackupRequest;
use Google\Cloud\Spanner\Admin\Database\V1\CopyBackupEncryptionConfig;
use Google\Protobuf\Timestamp;

/**
 * Copy a MR CMEK backup.
 * Example:
 * ```
 * copy_backup_with_mr_cmek($projectId, $instanceId, $sourceBackupId, $backupId, $kmsKeyNames);
 * ```
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $sourceBackupId The Spanner source backup ID.
 * @param string $backupId The Spanner backup ID.
 * @param string[] $kmsKeyNames The KMS keys used for encryption.
 */
/**
 * Create a copy MR CMEK backup from another source backup.
 * Example:
 * ```
 * copy_backup_with_mr_cmek($projectId, $destInstanceId, $destBackupId, $sourceInstanceId, $sourceBackupId, $kmsKeyNames);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $destInstanceId The Spanner instance ID where the copy backup will reside.
 * @param string $destBackupId The Spanner backup ID of the new backup to be created.
 * @param string $sourceInstanceId The Spanner instance ID of the source backup.
 * @param string $sourceBackupId The Spanner backup ID of the source.
* @param string[] $kmsKeyNames The KMS keys used for encryption.
 */
function copy_backup_with_mr_cmek(
    string $projectId,
    string $destInstanceId,
    string $destBackupId,
    string $sourceInstanceId,
    string $sourceBackupId,
    array $kmsKeyNames
): void {
    $databaseAdminClient = new DatabaseAdminClient();

    $destInstanceFullName = DatabaseAdminClient::instanceName($projectId, $destInstanceId);
    $expireTime = new Timestamp();
    $expireTime->setSeconds((new \DateTime('+8 hours'))->getTimestamp());
    $sourceBackupFullName = DatabaseAdminClient::backupName($projectId, $sourceInstanceId, $sourceBackupId);
    $request = new CopyBackupRequest([
        'source_backup' => $sourceBackupFullName,
        'parent' => $destInstanceFullName,
        'backup_id' => $destBackupId,
        'expire_time' => $expireTime,
        'encryption_config' => new CopyBackupEncryptionConfig([
            'kms_key_names' => $kmsKeyNames,
            'encryption_type' => CopyBackupEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION
        ])
    ]);

    $operationResponse = $databaseAdminClient->copyBackup($request);
    $operationResponse->pollUntilComplete();

    if (!$operationResponse->operationSucceeded()) {
        $error = $operationResponse->getError();
        printf('Backup not created due to error: %s.' . PHP_EOL, $error->getMessage());
        return;
    }
    $destBackupInfo = $operationResponse->getResult();
    $kmsKeyVersions = [];
    foreach ($destBackupInfo->getEncryptionInformation() as $encryptionInfo) {
        $kmsKeyVersions[] = $encryptionInfo->getKmsKeyVersion();
    }
    printf(
        'Backup %s of size %d bytes was copied at %d from the source backup %s using encryption keys %s' . PHP_EOL,
        basename($destBackupInfo->getName()),
        $destBackupInfo->getSizeBytes(),
        $destBackupInfo->getCreateTime()->getSeconds(),
        $sourceBackupId,
        print_r($kmsKeyVersions, true)
    );
    printf('Version time of the copied backup: %d' . PHP_EOL, $destBackupInfo->getVersionTime()->getSeconds());
}

Python

Para copiar una copia de seguridad con CMEK habilitada en una configuración de instancia multirregional, sigue estos pasos:

def copy_backup_with_multiple_kms_keys(
    instance_id, backup_id, source_backup_path, kms_key_names
):
    """Copies a backup."""

    from google.cloud.spanner_admin_database_v1.types import backup as backup_pb
    from google.cloud.spanner_admin_database_v1 import CopyBackupEncryptionConfig

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    encryption_config = {
        "encryption_type": CopyBackupEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION,
        "kms_key_names": kms_key_names,
    }

    # Create a backup object and wait for copy backup operation to complete.
    expire_time = datetime.utcnow() + timedelta(days=14)
    request = backup_pb.CopyBackupRequest(
        parent=database_admin_api.instance_path(spanner_client.project, instance_id),
        backup_id=backup_id,
        source_backup=source_backup_path,
        expire_time=expire_time,
        encryption_config=encryption_config,
    )

    operation = database_admin_api.copy_backup(request)

    # Wait for backup operation to complete.
    copy_backup = operation.result(2100)

    # Verify that the copy backup is ready.
    assert copy_backup.state == backup_pb.Backup.State.READY

    print(
        "Backup {} of size {} bytes was created at {} with version time {} using encryption keys {}".format(
            copy_backup.name,
            copy_backup.size_bytes,
            copy_backup.create_time,
            copy_backup.version_time,
            copy_backup.encryption_information,
        )
    )

Ruby

Para copiar una copia de seguridad con CMEK habilitada en una configuración de instancia multirregional, sigue estos pasos:

# project_id  = "Your Google Cloud project ID"
# instance_id = "The ID of the destination instance that will contain the backup copy"
# backup_id = "The ID of the backup copy"
# source_backup = "The source backup to be copied"
# kms_key_names = ["key1", "key2", "key3"]

require "google/cloud/spanner"
require "google/cloud/spanner/admin/database"

database_admin_client = Google::Cloud::Spanner::Admin::Database.database_admin

instance_path = database_admin_client.instance_path(
  project: project_id, instance: instance_id
)
backup_path = database_admin_client.backup_path project: project_id,
                                                instance: instance_id,
                                                backup: backup_id
source_backup = database_admin_client.backup_path project: project_id,
                                                  instance: instance_id,
                                                  backup: source_backup_id

expire_time = Time.now + (14 * 24 * 3600) # 14 days from now
encryption_config = {
  encryption_type: :CUSTOMER_MANAGED_ENCRYPTION,
  kms_key_names:    kms_key_names
}

job = database_admin_client.copy_backup parent: instance_path,
                                        backup_id: backup_id,
                                        source_backup: source_backup,
                                        expire_time: expire_time,
                                        encryption_config: encryption_config

puts "Copy backup operation in progress"

job.wait_until_done!

backup = database_admin_client.get_backup name: backup_path
puts "Backup #{backup_id} of size #{backup.size_bytes} bytes was copied at " \
     "#{backup.create_time} from #{source_backup} for version " \
     "#{backup.version_time} using encryption keys #{kms_key_names}"

Restaurar a partir de copia de seguridad

Puedes restaurar una copia de seguridad de una base de datos de Spanner en una base de datos nueva. De forma predeterminada, las bases de datos que se restauran a partir de una copia de seguridad usan la misma configuración de cifrado que la propia copia de seguridad, pero puedes anular este comportamiento especificando una configuración de cifrado diferente para la base de datos restaurada. Si la copia de seguridad está protegida por CMEK, la versión de la clave que se usó para crearla debe estar disponible para que se pueda descifrar.

Consola

Usa la consola para restaurar una copia de seguridad en una configuración de instancia regional.

  1. En la consola, ve a la página Instancias. Google Cloud

    Ir a instancias de Spanner

  2. Haz clic en la instancia que contiene la base de datos que quieres restaurar.

  3. Haz clic en la base de datos.

  4. En el panel de navegación, haz clic en Copia de seguridad o restauración.

  5. En la tabla Copias de seguridad, selecciona Acciones en la copia de seguridad que quieras restaurar y haz clic en Restaurar.

  6. Selecciona la instancia que quieras restaurar y asigna un nombre a la base de datos restaurada.

  7. Opcional: Si quieres usar otra configuración de cifrado con tu base de datos restaurada, haz clic en el control deslizante situado junto a Usar cifrado actual.

    a. Selecciona Clave de Cloud KMS.

    a. Seleccione una clave de la lista desplegable.

    La lista de claves se limita al proyecto Google Cloud actual. Para usar una clave de otro proyecto, crea la base de datos con la CLI de gcloud en lugar de con la consola. Google Cloud Google Cloud

  8. Haz clic en Restaurar.

gcloud

Para restaurar una copia de seguridad con una nueva configuración de cifrado, ejecuta el siguiente comando: gcloud spanner databases restore

gcloud spanner databases restore --async \
    --project=SPANNER_PROJECT_ID \
    --destination-instance=DESTINATION_INSTANCE_ID \
    --destination-database=DESTINATION_DATABASE_ID \
    --source-instance=SOURCE_INSTANCE_ID \
    --source-backup=SOURCE_BACKUP_NAME

Para verificar que la base de datos restaurada está cifrada con CMEK, sigue estos pasos:

gcloud spanner databases describe DATABASE \
    --project=SPANNER_PROJECT_ID \
    --instance=INSTANCE_ID

Para obtener más información, consulta Restaurar desde una copia de seguridad.

Bibliotecas de cliente

C#

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia regional, sigue estos pasos:


using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using System;
using System.Threading.Tasks;

public class RestoreDatabaseWithEncryptionAsyncSample
{
    public async Task<Database> RestoreDatabaseWithEncryptionAsync(string projectId, string instanceId, string databaseId, string backupId, CryptoKeyName kmsKeyName)
    {
        // Create a DatabaseAdminClient instance.
        DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();

        // Create the RestoreDatabaseRequest with encryption configuration.
        RestoreDatabaseRequest request = new RestoreDatabaseRequest
        {
            ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId),
            DatabaseId = databaseId,
            BackupAsBackupName = BackupName.FromProjectInstanceBackup(projectId, instanceId, backupId),
            EncryptionConfig = new RestoreDatabaseEncryptionConfig
            {
                EncryptionType = RestoreDatabaseEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,
                KmsKeyNameAsCryptoKeyName = kmsKeyName,
            }
        };
        // Execute the RestoreDatabase request.
        var operation = await databaseAdminClient.RestoreDatabaseAsync(request);

        Console.WriteLine("Waiting for the operation to finish.");

        // Poll until the returned long-running operation is complete.
        var completedResponse = await operation.PollUntilCompletedAsync();
        if (completedResponse.IsFaulted)
        {
            Console.WriteLine($"Error while restoring database: {completedResponse.Exception}");
            throw completedResponse.Exception;
        }

        var database = completedResponse.Result;
        var restoreInfo = database.RestoreInfo;
        Console.WriteLine($"Database {restoreInfo.BackupInfo.SourceDatabase} " +
            $"restored to {database.Name} " +
            $"from backup {restoreInfo.BackupInfo.Backup} " +
            $"using encryption key {database.EncryptionConfig.KmsKeyName}");
        return database;
    }
}

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia multirregional, sigue estos pasos:


using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class RestoreDatabaseWithMultiRegionEncryptionAsyncSample
{
    public async Task<Database> RestoreDatabaseWithMultiRegionEncryptionAsync(string projectId, string instanceId, string databaseId, string backupId, IEnumerable<CryptoKeyName> kmsKeyNames)
    {
        // Create a DatabaseAdminClient instance.
        DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();

        // Create the RestoreDatabaseRequest with encryption configuration.
        RestoreDatabaseRequest request = new RestoreDatabaseRequest
        {
            ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId),
            DatabaseId = databaseId,
            BackupAsBackupName = BackupName.FromProjectInstanceBackup(projectId, instanceId, backupId),
            EncryptionConfig = new RestoreDatabaseEncryptionConfig
            {
                EncryptionType = RestoreDatabaseEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,
                KmsKeyNamesAsCryptoKeyNames = { kmsKeyNames },
            }
        };
        // Execute the RestoreDatabase request.
        var operation = await databaseAdminClient.RestoreDatabaseAsync(request);

        Console.WriteLine("Waiting for the operation to finish.");

        // Poll until the returned long-running operation is complete.
        var completedResponse = await operation.PollUntilCompletedAsync();
        if (completedResponse.IsFaulted)
        {
            Console.WriteLine($"Error while restoring database: {completedResponse.Exception}");
            throw completedResponse.Exception;
        }

        var database = completedResponse.Result;
        var restoreInfo = database.RestoreInfo;
        Console.WriteLine($"Database {restoreInfo.BackupInfo.SourceDatabase} restored to {database.Name} from backup {restoreInfo.BackupInfo.Backup} using encryption keys {string.Join(", ", kmsKeyNames)}");
        return database;
    }
}

C++

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia regional, sigue estos pasos:

void RestoreDatabaseWithEncryptionKey(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    std::string const& project_id, std::string const& instance_id,
    std::string const& database_id, std::string const& backup_id,
    google::cloud::KmsKeyName const& encryption_key) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  google::cloud::spanner::Backup backup(database.instance(), backup_id);
  google::spanner::admin::database::v1::RestoreDatabaseRequest request;
  request.set_parent(database.instance().FullName());
  request.set_database_id(database.database_id());
  request.set_backup(backup.FullName());
  request.mutable_encryption_config()->set_encryption_type(
      google::spanner::admin::database::v1::RestoreDatabaseEncryptionConfig::
          CUSTOMER_MANAGED_ENCRYPTION);
  request.mutable_encryption_config()->set_kms_key_name(
      encryption_key.FullName());
  auto restored_db = client.RestoreDatabase(request).get();
  if (!restored_db) throw std::move(restored_db).status();
  std::cout << "Database";
  if (restored_db->restore_info().source_type() ==
      google::spanner::admin::database::v1::BACKUP) {
    auto const& backup_info = restored_db->restore_info().backup_info();
    std::cout << " " << backup_info.source_database() << " as of "
              << google::cloud::spanner::MakeTimestamp(
                     backup_info.version_time())
                     .value();
  }
  std::cout << " restored to " << restored_db->name();
  std::cout << " from backup " << backup.FullName();
  std::cout << " using encryption key " << encryption_key.FullName();
  std::cout << ".\n";
}

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia multirregional, sigue estos pasos:

void RestoreDatabaseWithMRCMEK(
    google::cloud::spanner_admin::DatabaseAdminClient client,
    BackupIdentifier const& src, std::string const& database_id,
    std::vector<google::cloud::KmsKeyName> const& encryption_keys) {
  google::cloud::spanner::Database database(src.project_id, src.instance_id,
                                            database_id);
  google::cloud::spanner::Backup backup(database.instance(), src.backup_id);
  google::spanner::admin::database::v1::RestoreDatabaseRequest request;
  request.set_parent(database.instance().FullName());
  request.set_database_id(database.database_id());
  request.set_backup(backup.FullName());
  request.mutable_encryption_config()->set_encryption_type(
      google::spanner::admin::database::v1::RestoreDatabaseEncryptionConfig::
          CUSTOMER_MANAGED_ENCRYPTION);
  for (google::cloud::KmsKeyName const& encryption_key : encryption_keys) {
    request.mutable_encryption_config()->add_kms_key_names(
        encryption_key.FullName());
  }
  auto restored_db = client.RestoreDatabase(request).get();
  if (!restored_db) throw std::move(restored_db).status();
  std::cout << "Database";
  if (restored_db->restore_info().source_type() ==
      google::spanner::admin::database::v1::BACKUP) {
    auto const& backup_info = restored_db->restore_info().backup_info();
    std::cout << " " << backup_info.source_database() << " as of "
              << google::cloud::spanner::MakeTimestamp(
                     backup_info.version_time())
                     .value();
  }
  std::cout << " restored to " << restored_db->name();
  std::cout << " from backup " << backup.FullName();
  PrintKmsKeys(encryption_keys);
}

Go

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia regional, sigue estos pasos:


import (
	"context"
	"fmt"
	"io"
	"regexp"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
)

func restoreBackupWithCustomerManagedEncryptionKey(ctx context.Context, w io.Writer, db, backupID, kmsKeyName string) error {
	// db = `projects/<project>/instances/<instance-id>/database/<database-id>`
	// backupID = `my-backup-id`
	// kmsKeyName = `projects/<project>/locations/<location>/keyRings/<key_ring>/cryptoKeys/<kms_key_name>`
	matches := regexp.MustCompile("^(.*)/databases/(.*)$").FindStringSubmatch(db)
	if matches == nil || len(matches) != 3 {
		return fmt.Errorf("restoreBackupWithCustomerManagedEncryptionKey: invalid database id %q", db)
	}
	instanceName := matches[1]
	databaseID := matches[2]
	backupName := instanceName + "/backups/" + backupID

	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return fmt.Errorf("restoreBackupWithCustomerManagedEncryptionKey.NewDatabaseAdminClient: %w", err)
	}
	defer adminClient.Close()

	// Restore a database from a backup using a Customer Managed Encryption Key.
	restoreOp, err := adminClient.RestoreDatabase(ctx, &adminpb.RestoreDatabaseRequest{
		Parent:     instanceName,
		DatabaseId: databaseID,
		Source: &adminpb.RestoreDatabaseRequest_Backup{
			Backup: backupName,
		},
		EncryptionConfig: &adminpb.RestoreDatabaseEncryptionConfig{
			EncryptionType: adminpb.RestoreDatabaseEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION,
			KmsKeyName:     kmsKeyName,
		},
	})
	if err != nil {
		return fmt.Errorf("restoreBackupWithCustomerManagedEncryptionKey.RestoreDatabase: %w", err)
	}
	// Wait for restore operation to complete.
	restoredDatabase, err := restoreOp.Wait(ctx)
	if err != nil {
		return fmt.Errorf("restoreBackupWithCustomerManagedEncryptionKey.Wait: %w", err)
	}
	// Get the information from the newly restored database.
	backupInfo := restoredDatabase.RestoreInfo.GetBackupInfo()
	fmt.Fprintf(w, "Database %s restored from backup %s using encryption key %s\n",
		backupInfo.SourceDatabase,
		backupInfo.Backup,
		restoredDatabase.EncryptionConfig.KmsKeyName)

	return nil
}

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia multirregional, sigue estos pasos:


import (
	"context"
	"fmt"
	"io"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
)

// restoreBackupWithCustomerManagedMultiRegionEncryptionKey restores a database from a backup using a Customer Managed Multi-Region Encryption Key.
func restoreBackupWithCustomerManagedMultiRegionEncryptionKey(ctx context.Context, w io.Writer, instName, databaseID string, backupID string, kmsKeyNames []string) error {
	// instName = `projects/my-project/instances/my-instance`
	// databaseID = `my-database`
	// backupID = `my-backup-id`
	// kmsKeyNames := []string{"projects/my-project/locations/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	//	 "projects/my-project/locations/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	//	 "projects/my-project/locations/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>",
	// }

	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return fmt.Errorf("restoreBackupWithCustomerManagedMultiRegionEncryptionKey.NewDatabaseAdminClient: %w", err)
	}
	defer adminClient.Close()

	// Restore a database from a backup using a Customer Managed Encryption Key.
	restoreOp, err := adminClient.RestoreDatabase(ctx, &adminpb.RestoreDatabaseRequest{
		Parent:     instName,
		DatabaseId: databaseID,
		Source: &adminpb.RestoreDatabaseRequest_Backup{
			Backup: fmt.Sprintf("%s/backups/%s", instName, backupID),
		},
		EncryptionConfig: &adminpb.RestoreDatabaseEncryptionConfig{
			EncryptionType: adminpb.RestoreDatabaseEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION,
			KmsKeyNames:    kmsKeyNames,
		},
	})
	if err != nil {
		return fmt.Errorf("restoreBackupWithCustomerManagedMultiRegionEncryptionKey.RestoreDatabase: %w", err)
	}

	// Wait for restore operation to complete.
	restoredDatabase, err := restoreOp.Wait(ctx)
	if err != nil {
		return fmt.Errorf("restoreBackupWithCustomerManagedMultiRegionEncryptionKey.Wait: %w", err)
	}

	// Get the information from the newly restored database.
	backupInfo := restoredDatabase.RestoreInfo.GetBackupInfo()
	fmt.Fprintf(w, "Database %s restored from backup %s using multi-region encryption keys %q\n",
		backupInfo.SourceDatabase,
		backupInfo.Backup,
		restoredDatabase.EncryptionConfig.GetKmsKeyNames())

	return nil
}

Java

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia regional, sigue estos pasos:


import static com.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION;

import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.spanner.admin.database.v1.BackupName;
import com.google.spanner.admin.database.v1.Database;
import com.google.spanner.admin.database.v1.InstanceName;
import com.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig;
import com.google.spanner.admin.database.v1.RestoreDatabaseRequest;
import java.util.concurrent.ExecutionException;

public class RestoreBackupWithEncryptionKey {

  static void restoreBackupWithEncryptionKey() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String backupId = "my-backup";
    String kmsKeyName =
        "projects/" + projectId + "/locations/<location>/keyRings/<keyRing>/cryptoKeys/<keyId>";

    try (Spanner spanner =
        SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
      restoreBackupWithEncryptionKey(
          adminClient,
          projectId,
          instanceId,
          backupId,
          databaseId,
          kmsKeyName);
    }
  }

  static Void restoreBackupWithEncryptionKey(DatabaseAdminClient adminClient,
      String projectId, String instanceId, String backupId, String restoreId, String kmsKeyName) {
    RestoreDatabaseRequest request =
        RestoreDatabaseRequest.newBuilder()
            .setParent(InstanceName.of(projectId, instanceId).toString())
            .setDatabaseId(restoreId)
            .setBackup(BackupName.of(projectId, instanceId, backupId).toString())
            .setEncryptionConfig(RestoreDatabaseEncryptionConfig.newBuilder()
                .setEncryptionType(CUSTOMER_MANAGED_ENCRYPTION).setKmsKeyName(kmsKeyName)).build();
    Database database;
    try {
      System.out.println("Waiting for operation to complete...");
      database = adminClient.restoreDatabaseAsync(request).get();
      ;
    } catch (ExecutionException e) {
      // If the operation failed during execution, expose the cause.
      throw SpannerExceptionFactory.asSpannerException(e.getCause());
    } catch (InterruptedException e) {
      // Throw when a thread is waiting, sleeping, or otherwise occupied,
      // and the thread is interrupted, either before or during the activity.
      throw SpannerExceptionFactory.propagateInterrupt(e);
    }

    System.out.printf(
        "Database %s restored to %s from backup %s using encryption key %s%n",
        database.getRestoreInfo().getBackupInfo().getSourceDatabase(),
        database.getName(),
        database.getRestoreInfo().getBackupInfo().getBackup(),
        database.getEncryptionConfig().getKmsKeyName()
    );
    return null;
  }
}

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia multirregional, sigue estos pasos:


import static com.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION;

import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.database.v1.BackupName;
import com.google.spanner.admin.database.v1.Database;
import com.google.spanner.admin.database.v1.InstanceName;
import com.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig;
import com.google.spanner.admin.database.v1.RestoreDatabaseRequest;
import java.util.concurrent.ExecutionException;

public class RestoreBackupWithMultiRegionEncryptionKey {

  static void restoreBackupWithMultiRegionEncryptionKey() {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "my-project";
    String instanceId = "my-instance";
    String databaseId = "my-database";
    String backupId = "my-backup";
    String[] kmsKeyNames =
        new String[] {
          "projects/" + projectId + "/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
          "projects/" + projectId + "/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
          "projects/" + projectId + "/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>"
        };

    try (Spanner spanner =
            SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
      restoreBackupWithMultiRegionEncryptionKey(
          adminClient, projectId, instanceId, backupId, databaseId, kmsKeyNames);
    }
  }

  static Void restoreBackupWithMultiRegionEncryptionKey(
      DatabaseAdminClient adminClient,
      String projectId,
      String instanceId,
      String backupId,
      String restoreId,
      String[] kmsKeyNames) {
    RestoreDatabaseRequest request =
        RestoreDatabaseRequest.newBuilder()
            .setParent(InstanceName.of(projectId, instanceId).toString())
            .setDatabaseId(restoreId)
            .setBackup(BackupName.of(projectId, instanceId, backupId).toString())
            .setEncryptionConfig(
                RestoreDatabaseEncryptionConfig.newBuilder()
                    .setEncryptionType(CUSTOMER_MANAGED_ENCRYPTION)
                    .addAllKmsKeyNames(ImmutableList.copyOf(kmsKeyNames)))
            .build();
    Database database;
    try {
      System.out.println("Waiting for operation to complete...");
      database = adminClient.restoreDatabaseAsync(request).get();
      ;
    } catch (ExecutionException e) {
      // If the operation failed during execution, expose the cause.
      throw SpannerExceptionFactory.asSpannerException(e.getCause());
    } catch (InterruptedException e) {
      // Throw when a thread is waiting, sleeping, or otherwise occupied,
      // and the thread is interrupted, either before or during the activity.
      throw SpannerExceptionFactory.propagateInterrupt(e);
    }

    System.out.printf(
        "Database %s restored to %s from backup %s using encryption keys %s%n",
        database.getRestoreInfo().getBackupInfo().getSourceDatabase(),
        database.getName(),
        database.getRestoreInfo().getBackupInfo().getBackup(),
        database.getEncryptionConfig().getKmsKeyNamesList());
    return null;
  }
}

Node.js

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia regional, sigue estos pasos:


// Imports the Google Cloud client library and precise date library
const {Spanner} = require('@google-cloud/spanner');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const backupId = 'my-backup';
// const keyName =
//   'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key';

// Creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner Database Admin Client object
const databaseAdminClient = spanner.getDatabaseAdminClient();

// Restore the database
console.log(
  `Restoring database ${databaseAdminClient.databasePath(
    projectId,
    instanceId,
    databaseId,
  )} from backup ${backupId}.`,
);
const [restoreOperation] = await databaseAdminClient.restoreDatabase({
  parent: databaseAdminClient.instancePath(projectId, instanceId),
  databaseId: databaseId,
  backup: databaseAdminClient.backupPath(projectId, instanceId, backupId),
  encryptionConfig: {
    encryptionType: 'CUSTOMER_MANAGED_ENCRYPTION',
    kmsKeyName: keyName,
  },
});

// Wait for restore to complete
console.log('Waiting for database restore to complete...');
await restoreOperation.promise();

console.log('Database restored from backup.');
const [metadata] = await databaseAdminClient.getDatabase({
  name: databaseAdminClient.databasePath(projectId, instanceId, databaseId),
});
console.log(
  `Database ${metadata.restoreInfo.backupInfo.sourceDatabase} was restored ` +
    `to ${databaseId} from backup ${metadata.restoreInfo.backupInfo.backup} ` +
    `using encryption key ${metadata.encryptionConfig.kmsKeyName}.`,
);

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia multirregional, sigue estos pasos:

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const backupId = 'my-backup';
// const kmsKeyNames =
//   'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key1,
//   projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key2';

// Imports the Google Cloud client library and precise date library
const {Spanner} = require('@google-cloud/spanner');

// Creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner Database Admin Client object
const databaseAdminClient = spanner.getDatabaseAdminClient();

async function restoreBackupWithMultipleKmsKeys() {
  // Restore the database
  console.log(
    `Restoring database ${databaseAdminClient.databasePath(
      projectId,
      instanceId,
      databaseId,
    )} from backup ${backupId}.`,
  );
  const [restoreOperation] = await databaseAdminClient.restoreDatabase({
    parent: databaseAdminClient.instancePath(projectId, instanceId),
    databaseId: databaseId,
    backup: databaseAdminClient.backupPath(projectId, instanceId, backupId),
    encryptionConfig: {
      encryptionType: 'CUSTOMER_MANAGED_ENCRYPTION',
      kmsKeyNames: kmsKeyNames.split(','),
    },
  });

  // Wait for restore to complete
  console.log('Waiting for database restore to complete...');
  await restoreOperation.promise();

  console.log('Database restored from backup.');
  const [metadata] = await databaseAdminClient.getDatabase({
    name: databaseAdminClient.databasePath(projectId, instanceId, databaseId),
  });
  console.log(
    `Database ${metadata.restoreInfo.backupInfo.sourceDatabase} was restored ` +
      `to ${databaseId} from backup ${metadata.restoreInfo.backupInfo.backup} ` +
      `using encryption key ${metadata.encryptionConfig.kmsKeyNames}.`,
  );
}
restoreBackupWithMultipleKmsKeys();

PHP

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia regional, sigue estos pasos:

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\RestoreDatabaseEncryptionConfig;
use Google\Cloud\Spanner\Admin\Database\V1\RestoreDatabaseRequest;

/**
 * Restore a database from a backup.
 * Example:
 * ```
 * restore_backup_with_encryption_key($projectId, $instanceId, $databaseId, $backupId, $kmsKeyName);
 * ```
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 * @param string $backupId The Spanner backup ID.
 * @param string $kmsKeyName The KMS key used for encryption.
 */
function restore_backup_with_encryption_key(
    string $projectId,
    string $instanceId,
    string $databaseId,
    string $backupId,
    string $kmsKeyName
): void {
    $databaseAdminClient = new DatabaseAdminClient();
    $instanceFullName = DatabaseAdminClient::instanceName($projectId, $instanceId);
    $backupFullName = DatabaseAdminClient::backupName($projectId, $instanceId, $backupId);
    $request = new RestoreDatabaseRequest([
        'parent' => $instanceFullName,
        'database_id' => $databaseId,
        'backup' => $backupFullName,
        'encryption_config' => new RestoreDatabaseEncryptionConfig([
            'kms_key_name' => $kmsKeyName,
            'encryption_type' => RestoreDatabaseEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION
        ])
    ]);

    // Create restore operation
    $operation = $databaseAdminClient->restoreDatabase($request);

    print('Waiting for operation to complete...' . PHP_EOL);
    $operation->pollUntilComplete();

    // Reload new database and get restore info
    $database = $operation->operationSucceeded() ? $operation->getResult() : null;
    $restoreInfo = $database->getRestoreInfo();
    $backupInfo = $restoreInfo->getBackupInfo();
    $sourceDatabase = $backupInfo->getSourceDatabase();
    $sourceBackup = $backupInfo->getBackup();
    $encryptionConfig = $database->getEncryptionConfig();
    printf(
        'Database %s restored from backup %s using encryption key %s' . PHP_EOL,
        $sourceDatabase, $sourceBackup, $encryptionConfig->getKmsKeyName()
    );
}

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia multirregional, sigue estos pasos:

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\RestoreDatabaseEncryptionConfig;
use Google\Cloud\Spanner\Admin\Database\V1\RestoreDatabaseRequest;

/**
 * Restore a MR CMEK database from a backup.
 * Example:
 * ```
 * restore_backup_with_mr_cmek($projectId, $instanceId, $databaseId, $backupId, $kmsKeyNames);
 * ```
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 * @param string $backupId The Spanner backup ID.
 * @param string[] $kmsKeyNames The KMS keys used for encryption.
 */
function restore_backup_with_mr_cmek(
    string $projectId,
    string $instanceId,
    string $databaseId,
    string $backupId,
    array $kmsKeyNames
): void {
    $databaseAdminClient = new DatabaseAdminClient();
    $instanceFullName = DatabaseAdminClient::instanceName($projectId, $instanceId);
    $backupFullName = DatabaseAdminClient::backupName($projectId, $instanceId, $backupId);
    $request = new RestoreDatabaseRequest([
        'parent' => $instanceFullName,
        'database_id' => $databaseId,
        'backup' => $backupFullName,
        'encryption_config' => new RestoreDatabaseEncryptionConfig([
            'kms_key_names' => $kmsKeyNames,
            'encryption_type' => RestoreDatabaseEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION
        ])
    ]);

    // Create restore operation
    $operation = $databaseAdminClient->restoreDatabase($request);

    print('Waiting for operation to complete...' . PHP_EOL);
    $operation->pollUntilComplete();

    // Reload new database and get restore info
    $database = $operation->operationSucceeded() ? $operation->getResult() : null;
    $restoreInfo = $database->getRestoreInfo();
    $backupInfo = $restoreInfo->getBackupInfo();
    $sourceDatabase = $backupInfo->getSourceDatabase();
    $sourceBackup = $backupInfo->getBackup();
    $encryptionConfig = $database->getEncryptionConfig();
    printf(
        'Database %s restored from backup %s using encryption keys %s' . PHP_EOL,
        $sourceDatabase, $sourceBackup, print_r($encryptionConfig->getKmsKeyNames(), true)
    );
}

Python

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia regional, sigue estos pasos:

def restore_database_with_encryption_key(
    instance_id, new_database_id, backup_id, kms_key_name
):
    """Restores a database from a backup using a Customer Managed Encryption Key (CMEK)."""
    from google.cloud.spanner_admin_database_v1 import (
        RestoreDatabaseEncryptionConfig,
        RestoreDatabaseRequest,
    )

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    # Start restoring an existing backup to a new database.
    encryption_config = {
        "encryption_type": RestoreDatabaseEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION,
        "kms_key_name": kms_key_name,
    }

    request = RestoreDatabaseRequest(
        parent=database_admin_api.instance_path(spanner_client.project, instance_id),
        database_id=new_database_id,
        backup=database_admin_api.backup_path(
            spanner_client.project, instance_id, backup_id
        ),
        encryption_config=encryption_config,
    )
    operation = database_admin_api.restore_database(request)

    # Wait for restore operation to complete.
    db = operation.result(1600)

    # Newly created database has restore information.
    restore_info = db.restore_info
    print(
        "Database {} restored to {} from backup {} with using encryption key {}.".format(
            restore_info.backup_info.source_database,
            new_database_id,
            restore_info.backup_info.backup,
            db.encryption_config.kms_key_name,
        )
    )

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia multirregional, sigue estos pasos:

def restore_database_with_multiple_kms_keys(
    instance_id, new_database_id, backup_id, kms_key_names
):
    """Restores a database from a backup using a Customer Managed Encryption Key (CMEK)."""
    from google.cloud.spanner_admin_database_v1 import (
        RestoreDatabaseEncryptionConfig,
        RestoreDatabaseRequest,
    )

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    # Start restoring an existing backup to a new database.
    encryption_config = {
        "encryption_type": RestoreDatabaseEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION,
        "kms_key_names": kms_key_names,
    }

    request = RestoreDatabaseRequest(
        parent=database_admin_api.instance_path(spanner_client.project, instance_id),
        database_id=new_database_id,
        backup=database_admin_api.backup_path(
            spanner_client.project, instance_id, backup_id
        ),
        encryption_config=encryption_config,
    )
    operation = database_admin_api.restore_database(request)

    # Wait for restore operation to complete.
    db = operation.result(1600)

    # Newly created database has restore information.
    restore_info = db.restore_info
    print(
        "Database {} restored to {} from backup {} with using encryption key {}.".format(
            restore_info.backup_info.source_database,
            new_database_id,
            restore_info.backup_info.backup,
            db.encryption_config.kms_key_names,
        )
    )

Ruby

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia regional, sigue estos pasos:

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID of where to restore"
# backup_id = "Your Spanner backup ID"
# kms_key_name = "Your backup encryption database KMS key"

require "google/cloud/spanner"
require "google/cloud/spanner/admin/database"

database_admin_client = Google::Cloud::Spanner::Admin::Database.database_admin

instance_path = database_admin_client.instance_path project: project_id, instance: instance_id

db_path = database_admin_client.database_path project: project_id,
                                              instance: instance_id,
                                              database: database_id

backup_path = database_admin_client.backup_path project: project_id,
                                                instance: instance_id,
                                                backup: backup_id

encryption_config = {
  encryption_type: :CUSTOMER_MANAGED_ENCRYPTION,
  kms_key_name:    kms_key_name
}
job = database_admin_client.restore_database parent: instance_path,
                                             database_id: database_id,
                                             backup: backup_path,
                                             encryption_config: encryption_config

puts "Waiting for restore backup operation to complete"

job.wait_until_done!
database = database_admin_client.get_database name: db_path
restore_info = database.restore_info
puts "Database #{restore_info.backup_info.source_database} was restored to #{database_id} from backup #{restore_info.backup_info.backup} using encryption key #{database.encryption_config.kms_key_name}"

Para restaurar una copia de seguridad habilitada para CMEK en una configuración de instancia multirregional, sigue estos pasos:

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID of where to restore"
# backup_id = "Your Spanner backup ID"
# kms_key_names = ["key1", "key2", "key3"]

require "google/cloud/spanner"
require "google/cloud/spanner/admin/database"

database_admin_client = Google::Cloud::Spanner::Admin::Database.database_admin

instance_path = database_admin_client.instance_path(
  project: project_id, instance: instance_id
)

db_path = database_admin_client.database_path project: project_id,
                                              instance: instance_id,
                                              database: database_id

backup_path = database_admin_client.backup_path project: project_id,
                                                instance: instance_id,
                                                backup: backup_id

encryption_config = {
  encryption_type: :CUSTOMER_MANAGED_ENCRYPTION,
  kms_key_names:    kms_key_names
}
job = database_admin_client.restore_database(
  parent: instance_path,
  database_id: database_id,
  backup: backup_path,
  encryption_config: encryption_config
)

puts "Waiting for restore backup operation to complete"

job.wait_until_done!
database = database_admin_client.get_database name: db_path
restore_info = database.restore_info
puts "Database #{restore_info.backup_info.source_database} was restored " \
     "to #{database_id} from backup #{restore_info.backup_info.backup} " \
     "using encryption key #{database.encryption_config.kms_key_names}"

Ver los registros de auditoría de la clave de Cloud KMS

  1. Asegúrate de que el registro esté habilitado para la API Cloud KMS en tu proyecto.

  2. En la Google Cloud consola, ve a Explorador de registros.

    Ir a Explorador de registros

  3. Limita las entradas de registro a tu clave de Cloud KMS añadiendo las siguientes líneas al creador de consultas:

    resource.type="cloudkms_cryptokey"
    resource.labels.location="KMS_KEY_LOCATION"
    resource.labels.key_ring_id="KMS_KEY_RING_ID"
    resource.labels.crypto_key_id="KMS_KEY_ID"
    

    En condiciones normales, las acciones de cifrado y descifrado se registran con la gravedad INFO. Estas entradas se registran cuando las zonas de tu instancia de Spanner consultan la clave de Cloud KMS cada cinco minutos aproximadamente.

    Si Spanner no puede acceder a la clave, las operaciones se registran como ERROR.