Vom Kunden verwaltete Verschlüsselungsschlüssel verwenden

Auf dieser Seite wird beschrieben, wie Sie vom Kunden verwaltete Verschlüsselungsschlüssel (CMEK) für Cloud Spanner verwenden.

Weitere Informationen zu CMEK finden Sie unter Vom Kunden verwaltete Verschlüsselungsschlüssel.

CMEK-fähige Datenbank erstellen

  1. Erstellen Sie einen Schlüssel im Cloud Key Management Service (Cloud KMS). Cloud Spanner unterstützt:

    Der Schlüssel muss sich am selben Speicherort wie Ihre Cloud Spanner-Instanz befinden. Wenn Ihre Cloud Spanner-Instanzkonfiguration beispielsweise us-west1 ist, muss Ihr Schlüsselbund-Speicherort ebenfalls us-west1 sein.

    Nicht jede Multi-Region-Instanzkonfiguration von Cloud Spanner hat einen entsprechenden Schlüsselbund in Cloud KMS. Sie können in diesen Cloud Spanner-Instanzen keine CMEK-fähigen Datenbanken erstellen.

    Wenn Sie bereits einen Cloud KMS-Schlüssel an der richtigen Stelle haben, können Sie diesen Schritt überspringen.

    Weitere Informationen finden Sie in den folgenden Ressourcen:

  2. Cloud Spanner Zugriff auf den Schlüssel gewähren

    1. Erstellen Sie in Cloud Shell das von Google verwaltete Dienstkonto und rufen Sie es auf oder zeigen Sie es an, wenn das Konto bereits vorhanden ist:

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

      Wenn Sie aufgefordert werden, die Komponente gcloud Beta Commands zu installieren, geben Sie Y ein. Nach der Installation wird der Befehl automatisch neu gestartet.

      Der Befehl gcloud services identity erstellt oder ruft das spezielle von Google verwaltete Dienstkonto ab, mit dem Cloud Spanner auf die Cloud zugreifen kann. KMS-Schlüssel in Ihrem Namen an.

      Die Dienstkonto-ID hat das Format einer E-Mail-Adresse:

      Service identity created: service-xxx@gcp-sa-spanner.iam.gserviceaccount.com
      
    2. Weisen Sie dem Dienstkonto die Rolle cloudkms.cryptoKeyEncrypterDecrypter zu:

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

      Sie sehen hier Folgendes:

      Updated IAM policy for key [my-kms-key]
      

      Diese Rolle gewährleistet, dass das Dienstkonto die Berechtigung zum Verschlüsseln und Entschlüsseln mit dem Cloud KMS-Schlüssel hat. Weitere Informationen finden Sie unter Berechtigungen und Rollen in Cloud KMS.

  3. Erstellen Sie die Datenbank und geben Sie Ihren Cloud KMS-Schlüssel an.

    Console

    1. Rufen Sie in der Google Cloud Console die Seite Cloud Spanner-Instanzen auf.

    Zur Cloud Console

    2. Klicken Sie auf den Instanznamen, in dem die Datenbank erstellt werden soll.

    3. Klicken Sie auf Datenbank erstellen und füllen Sie die Pflichtfelder aus.

    4. Klicken Sie auf Verschlüsselungsoptionen anzeigen.

    5 Wählen Sie Vom Kunden verwalteten Verschlüsselungsschlüssel (CMEK) verwenden aus.

    6. Wählen Sie Ihren Schlüssel aus der Drop-down-Liste aus.

    Die Liste der Schlüssel ist auf das aktuelle Google Cloud-Projekt beschränkt. Wenn Sie einen Schlüssel aus einem anderen Google Cloud-Projekt verwenden möchten, erstellen Sie die Datenbank mit gcloud anstelle der Cloud Console.

    Nachdem die Datenbank erstellt wurde, können Sie auf der Seite Datenbankdetails prüfen, ob CMEK aktiviert ist.

    gcloud

    gcloud spanner databases create example-db \
         --project=my-spanner-project \
        --instance=my-spanner-instance \
        --ddl="CREATE TABLE Users (Id INT64 NOT NULL, FirstName STRING(100) NOT NULL, LastName STRING(100) NOT NULL,) PRIMARY KEY (Id)" \
        --kms-project=my-kms-project \
        --kms-location=my-kms-key-location \
        --kms-keyring=my-kms-key-ring \
        --kms-key=my-kms-key
    

    So prüfen Sie, ob eine Datenbank CMEK-fähig ist:

    gcloud spanner databases describe example-db \
        --project=my-spanner-project \
        --instance=my-spanner-instance
    

    CMEK-fähige Datenbanken enthalten ein Feld für encryptionConfig, wie in diesem Beispiel gezeigt:

    encryptionConfig:
            kmsKeyName: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
    

    C#

    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;
        }
    }
    

    C++

    void CreateDatabaseWithEncryptionKey(
        google::cloud::spanner::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);
      std::vector<std::string> extra_statements;
      extra_statements.emplace_back(R"""(
          CREATE TABLE Singers (
              SingerId   INT64 NOT NULL,
              FirstName  STRING(1024),
              LastName   STRING(1024),
              SingerInfo BYTES(MAX)
          ) PRIMARY KEY (SingerId))""");
      extra_statements.emplace_back(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)""");
      auto db =
          client
              .CreateDatabase(
                  database, std::move(extra_statements),
                  google::cloud::spanner::CustomerManagedEncryption(encryption_key))
              .get();
      if (!db) throw std::runtime_error(db.status().message());
      std::cout << "Database " << db->name() << " created";
      std::cout << " using encryption key " << encryption_key.FullName();
      std::cout << ".\n";
    }

    Go

    import (
    	"context"
    	"fmt"
    	"io"
    	"regexp"
    
    	database "cloud.google.com/go/spanner/admin/database/apiv1"
    	adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
    )
    
    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: %v", 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: %v", err)
    	}
    	dbObj, err := op.Wait(ctx)
    	if err != nil {
    		return fmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey.Wait: %v", err)
    	}
    	fmt.Fprintf(w, "Created database [%s] using encryption key %q\n", dbObj.Name, dbObj.EncryptionConfig.KmsKeyName)
    	return nil
    }
    

    Java

    
    import com.google.api.gax.longrunning.OperationFuture;
    import com.google.cloud.spanner.Database;
    import com.google.cloud.spanner.DatabaseAdminClient;
    import com.google.cloud.spanner.DatabaseId;
    import com.google.cloud.spanner.Spanner;
    import com.google.cloud.spanner.SpannerExceptionFactory;
    import com.google.cloud.spanner.SpannerOptions;
    import com.google.cloud.spanner.encryption.EncryptionConfigs;
    import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
    import java.util.Arrays;
    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.getDatabaseAdminClient();
          createDatabaseWithEncryptionKey(
              adminClient,
              projectId,
              instanceId,
              databaseId,
              kmsKeyName);
        }
      }
    
      static void createDatabaseWithEncryptionKey(DatabaseAdminClient adminClient,
          String projectId, String instanceId, String databaseId, String kmsKeyName) {
        final Database databaseToCreate = adminClient
            .newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId))
            .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(kmsKeyName))
            .build();
        final OperationFuture<Database, CreateDatabaseMetadata> operation = adminClient
            .createDatabase(databaseToCreate, Arrays.asList(
                "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"
            ));
        try {
          System.out.println("Waiting for operation to complete...");
          Database createdDatabase = operation.get(120, TimeUnit.SECONDS);
    
          System.out.printf(
              "Database %s created with encryption key %s%n",
              createdDatabase.getId(),
              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);
        }
      }
    }

    Knoten

    // Imports the Google Cloud client 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 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 instance
    const instance = spanner.instance(instanceId);
    
    const request = {
      encryptionConfig: {
        kmsKeyName: keyName,
      },
    };
    
    // Creates a database
    const [database, operation] = await instance.createDatabase(
      databaseId,
      request
    );
    
    console.log(`Waiting for operation on ${database.id} to complete...`);
    await operation.promise();
    
    console.log(`Created database ${databaseId} on instance ${instanceId}.`);
    
    // Get encryption key
    const [data] = await database.get();
    
    console.log(
      `Database encrypted with key ${data.metadata.encryptionConfig.kmsKeyName}.`
    );

    PHP

    use Google\Cloud\Spanner\SpannerClient;
    
    /**
     * Creates an encrypted database with tables for sample data.
     * Example:
     * ```
     * create_database_with_encryption_key($instanceId, $databaseId, $kmsKeyName);
     * ```
     *
     * @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($instanceId, $databaseId, $kmsKeyName)
    {
        $spanner = new SpannerClient();
        $instance = $spanner->instance($instanceId);
    
        if (!$instance->exists()) {
            throw new \LogicException("Instance $instanceId does not exist");
        }
    
        $operation = $instance->createDatabase($databaseId, [
            '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"
            ],
            'encryptionConfig' => ['kmsKeyName' => $kmsKeyName]
        ]);
    
        print('Waiting for operation to complete...' . PHP_EOL);
        $operation->pollUntilComplete();
    
        $database = $instance->database($databaseId);
        printf(
            'Created database %s on instance %s with encryption key %s' . PHP_EOL,
            $databaseId,
            $instanceId,
            $database->info()['encryptionConfig']['kmsKeyName']
        );
    }
    

    Python

    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)."""
        spanner_client = spanner.Client()
        instance = spanner_client.instance(instance_id)
    
        database = instance.database(
            database_id,
            ddl_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},
        )
    
        operation = database.create()
    
        print("Waiting for operation to complete...")
        operation.result(OPERATION_TIMEOUT_SECONDS)
    
        print("Database {} created with encryption key {}".format(
            database.name, database.encryption_config.kms_key_name))
    
    

    Ruby

    # 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"
    
    spanner  = Google::Cloud::Spanner.new project: project_id
    instance = spanner.instance instance_id
    
    job = instance.create_database database_id, 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 = job.database
    
    puts "Database #{database.database_id} created with encryption key #{database.encryption_config.kms_key_name}"
    

Verwendete Schlüsselversionen aufrufen

Informationen zu Schlüsselversionen stammen aus dem Feld encryption_info der Datenbank.

Wenn sich die Schlüsselversion einer Datenbank ändert, wird die Änderung nicht sofort an encryption_info weitergegeben. Es kann etwas dauern, bis die Änderung im Infofeld widergespiegelt wird.

Console

Verschlüsselungsinformationen werden auf der Seite Datenbankdetails angezeigt.

gcloud

Rufen Sie den encryption_info einer Datenbank durch einen Aufruf von databases describe oder databases list ab. Beispiel:

gcloud spanner databases describe example-db \
    --project=my-spanner-project \
    --instance=my-spanner-instance

Hier ist die Ausgabe:

name: projects/my-project/instances/test-instance/databases/example-db
encryptionConfig:
  kmsKeyName: projects/google.com:cloud-spanner-demo/locations/us-central1/keyRings/cmek_demo/cryptoKeys/backup-key
encryptionInfo:
  encryptionType: CUSTOMER_MANAGED_ENCRYPTION

Schlüssel deaktivieren

  1. Deaktivieren Sie die verwendeten Schlüsselversionen gemäß dieser Anleitung für jede Schlüsselversion.

  2. Warten Sie, bis die Änderung wirksam wird. Die Deaktivierung eines Schlüssels kann bis zu 3 Stunden dauern.

    Bestätigen Sie, dass der Zugriff auf die Daten nicht mehr möglich ist:

    gcloud spanner databases execute-sql example-db \
        --project=my-spanner-project \
        --instance=my-spanner-instance \
        --sql='SELECT * FROM Users'
    

    Der folgende Fehler wird angezeigt: KMS key required by the Spanner resource is not accessible..

Schlüssel aktivieren

  1. Folgen Sie dieser Anleitung, um die von der Datenbank verwendeten Schlüsselversionen für jede Schlüsselversion zu aktivieren.

  2. Warten Sie, bis die Änderung wirksam wird. Das Aktivieren eines Schlüssels kann bis zu 3 Stunden dauern.

    Prüfen Sie, ob der Zugriff auf Daten möglich ist:

    gcloud spanner databases execute-sql example-db \
        --project=my-spanner-project \
        --instance=my-spanner-instance \
        --sql='SELECT * FROM Users'
    

    Wenn die Änderung wirksam ist, wird der Befehl erfolgreich ausgeführt.

Datenbank sichern

Standardmäßig verwenden Sicherungen, die aus einer Datenbank erstellt werden, dieselbe Verschlüsselungskonfiguration wie die Datenbank selbst. Sie können optional eine andere Verschlüsselungskonfiguration für eine Sicherung angeben.

So erstellen Sie eine Sicherung:

Console

  1. Rufen Sie in der Cloud Console die Seite Datenbankdetails auf.

    Zur Cloud Console

  2. Klicken Sie auf dem Tab Sicherung/Wiederherstellung auf Erstellen.

  3. Geben Sie einen Namen für die Sicherung ein und wählen Sie ein Ablaufdatum aus.

  4. Wählen Sie Vom Kunden verwalteten Verschlüsselungsschlüssel (CMEK) verwenden und einen Schlüssel aus der Drop-down-Liste aus.

  5. Klicken Sie auf Erstellen.

Die Tabelle Sicherungen enthält Verschlüsselungsinformationen für jede Sicherung.

gcloud

gcloud spanner backups create my-backup \
    --project=my-spanner-project \
    --instance=my-spanner-instance \
    --database=example-db  \
    --retention-period=1y --async

So prüfen Sie, ob die erstellte Sicherung CMEK-verschlüsselt ist:

gcloud spanner backups describe my-backup \
    --project=my-spanner-project \
    --instance=my-spanner-instance

C#

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;
    }
}

C++

void CreateBackupWithEncryptionKey(
    google::cloud::spanner::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);
  auto backup =
      client
          .CreateBackup(
              database, backup_id, expire_time, version_time,
              google::cloud::spanner::CustomerManagedEncryption(encryption_key))
          .get();
  if (!backup) throw std::runtime_error(backup.status().message());
  std::cout
      << "Backup " << backup->name() << " of " << backup->database()
      << " of size " << backup->size_bytes() << " bytes"
      << " was created at "
      << google::cloud::spanner::MakeTimestamp(backup->create_time()).value()
      << " using encryption key " << encryption_key.FullName() << ".\n";
}

Go


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

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	pbt "github.com/golang/protobuf/ptypes/timestamp"
	adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
)

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: %v", 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: %v", err)
	}
	// Wait for backup operation to complete.
	backup, err := op.Wait(ctx)
	if err != nil {
		return fmt.Errorf("createBackupWithCustomerManagedEncryptionKey.Wait: %v", 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
}

Java


import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.Timestamp;
import com.google.cloud.spanner.Backup;
import com.google.cloud.spanner.BackupId;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.encryption.EncryptionConfigs;
import com.google.spanner.admin.database.v1.CreateBackupMetadata;
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() throws InterruptedException {
    // 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.getDatabaseAdminClient();
      createBackupWithEncryptionKey(
          adminClient,
          projectId,
          instanceId,
          databaseId,
          backupId,
          kmsKeyName);
    }
  }

  static Void createBackupWithEncryptionKey(DatabaseAdminClient adminClient,
      String projectId, String instanceId, String databaseId, String backupId, String kmsKeyName)
      throws InterruptedException {
    // Set expire time to 14 days from now.
    final Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert(
        System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS));
    final Backup backupToCreate = adminClient
        .newBackupBuilder(BackupId.of(projectId, instanceId, backupId))
        .setDatabase(DatabaseId.of(projectId, instanceId, databaseId))
        .setExpireTime(expireTime)
        .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(kmsKeyName))
        .build();
    final OperationFuture<Backup, CreateBackupMetadata> operation = adminClient
        .createBackup(backupToCreate);

    Backup backup;
    try {
      System.out.println("Waiting for operation to complete...");
      backup = operation.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.getId().getName(),
        backup.getSize(),
        LocalDateTime.ofEpochSecond(
            backup.getProto().getCreateTime().getSeconds(),
            backup.getProto().getCreateTime().getNanos(),
            OffsetDateTime.now().getOffset()),
        kmsKeyName
    );

    return null;
  }
}

Knoten

// Imports the Google Cloud client library and precise date library
const {Spanner} = 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 versionTime = Date.now() - 1000 * 60 * 60 * 24; // One day ago
// 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 instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);

const backup = instance.backup(backupId);

// Creates a new backup of the database
try {
  console.log(`Creating backup of database ${database.formattedName_}.`);
  const databasePath = database.formattedName_;
  // 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 backup.create({
    databasePath: databasePath,
    expireTime: expireTime,
    encryptionConfig: {
      encryptionType: 'CUSTOMER_MANAGED_ENCRYPTION',
      kmsKeyName: keyName,
    },
  });

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

  // Verify backup is ready
  const [backupInfo] = await backup.getMetadata();
  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 database when finished.
  await database.close();
}

PHP

use Google\Cloud\Spanner\Admin\Database\V1\CreateBackupEncryptionConfig;
use Google\Cloud\Spanner\Backup;
use Google\Cloud\Spanner\SpannerClient;

/**
 * Create an encrypted backup.
 * Example:
 * ```
 * create_backup_with_encryption_key($instanceId, $databaseId, $backupId, $kmsKeyName);
 * ```
 *
 * @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($instanceId, $databaseId, $backupId, $kmsKeyName)
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);

    $expireTime = new \DateTime('+14 days');
    $backup = $instance->backup($backupId);
    $operation = $backup->create($database->name(), $expireTime, [
        'encryptionConfig' => [
            'kmsKeyName' => $kmsKeyName,
            'encryptionType' => CreateBackupEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION
        ]
    ]);

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

    $backup->reload();
    $ready = ($backup->state() == Backup::STATE_READY);

    if ($ready) {
        print('Backup is ready!' . PHP_EOL);
        $info = $backup->info();
        printf(
            'Backup %s of size %d bytes was created at %s using encryption key %s' . PHP_EOL,
            basename($info['name']), $info['sizeBytes'], $info['createTime'], $kmsKeyName);
    } else {
        print('Backup is not ready!' . PHP_EOL);
    }
}

Python

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

    spanner_client = spanner.Client()
    instance = spanner_client.instance(instance_id)
    database = instance.database(database_id)

    # 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,
    }
    backup = instance.backup(backup_id, database=database, expire_time=expire_time, encryption_config=encryption_config)
    operation = backup.create()

    # Wait for backup operation to complete.
    operation.result(1200)

    # Verify that the backup is ready.
    backup.reload()
    assert backup.is_ready() is True

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

Ruby

# 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"

spanner = Google::Cloud::Spanner.new project: project_id
client = spanner.client instance_id, database_id
instance = spanner.instance instance_id
database = instance.database database_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.create_backup backup_id, expire_time, version_time: version_time, encryption_config: encryption_config

puts "Backup operation in progress"

job.wait_until_done!

backup = instance.backup backup_id
puts "Backup #{backup.backup_id} of size #{backup.size_in_bytes} bytes was created at #{backup.create_time} using encryption key #{kms_key_name}"

Daten aus einer Sicherung wiederherstellen

Standardmäßig verwenden Datenbanken, die aus einer Sicherung wiederhergestellt werden, dieselbe Verschlüsselungskonfiguration wie die Sicherung selbst. Sie können dieses Verhalten jedoch überschreiben, indem Sie für die wiederhergestellte Datenbank eine andere Verschlüsselungskonfiguration angeben. Wenn die Sicherung durch CMEK geschützt ist, muss die zum Erstellen der Sicherung verwendete Schlüsselversion verfügbar sein, damit sie entschlüsselt werden kann.

So stellen Sie eine Datenbank wieder her:

Console

  1. Öffnen Sie in der Cloud Console die Seite Instanzdetails.

    Zur Cloud Console

  2. Wählen Sie auf dem Tab Sicherung/Wiederherstellung eine Sicherung aus und klicken Sie auf Wiederherstellen.

  3. Wählen Sie die wiederherzustellende Instanz aus und benennen Sie die wiederhergestellte Datenbank.

  4. Wenn Sie CMEK mit der wiederhergestellten Datenbank verwenden möchten, wählen Sie Vom Kunden verwalteten Verschlüsselungsschlüssel (CMEK) verwenden und einen Schlüssel aus der Drop-down-Liste aus.

gcloud

gcloud spanner databases restore --async \
    --project=my-spanner-project \
    --destination-instance=destination-instance \
    --destination-database=example-db-restored \
    --source-instance=my-spanner-instance \
    --source-backup=my-backup

Prüfen Sie, ob die wiederhergestellte Datenbank CMEK-verschlüsselt ist:

gcloud spanner databases describe example-db-restored \
    --project=my-spanner-project \
    --instance=destination-instance

Weitere Informationen finden Sie unter Datenbank aus einer Sicherung wiederherstellen.

C#

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;
    }
}

C++

void RestoreDatabaseWithEncryptionKey(
    google::cloud::spanner::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);
  auto restored_db =
      client
          .RestoreDatabase(
              database, backup,
              google::cloud::spanner::CustomerManagedEncryption(encryption_key))
          .get();
  if (!restored_db) {
    throw std::runtime_error(restored_db.status().message());
  }
  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";
}

Go


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

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
)

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: %v", 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: %v", err)
	}
	// Wait for restore operation to complete.
	restoredDatabase, err := restoreOp.Wait(ctx)
	if err != nil {
		return fmt.Errorf("restoreBackupWithCustomerManagedEncryptionKey.Wait: %v", 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
}

Java


import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.spanner.BackupId;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Restore;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.encryption.EncryptionConfigs;
import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata;
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.getDatabaseAdminClient();
      restoreBackupWithEncryptionKey(
          adminClient,
          projectId,
          instanceId,
          backupId,
          databaseId,
          kmsKeyName);
    }
  }

  static Void restoreBackupWithEncryptionKey(DatabaseAdminClient adminClient,
      String projectId, String instanceId, String backupId, String restoreId, String kmsKeyName) {
    final Restore restore = adminClient
        .newRestoreBuilder(
            BackupId.of(projectId, instanceId, backupId),
            DatabaseId.of(projectId, instanceId, restoreId))
        .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(kmsKeyName))
        .build();
    final OperationFuture<Database, RestoreDatabaseMetadata> operation = adminClient
        .restoreDatabase(restore);

    Database database;
    try {
      System.out.println("Waiting for operation to complete...");
      database = operation.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().getSourceDatabase(),
        database.getId(),
        database.getRestoreInfo().getBackup(),
        database.getEncryptionConfig().getKmsKeyName()
    );
    return null;
  }
}

Knoten

// 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 instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);

// Restore the database
console.log(
  `Restoring database ${database.formattedName_} from backup ${backupId}.`
);
const [, restoreOperation] = await database.restore(
  `projects/${projectId}/instances/${instanceId}/backups/${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 restoreInfo = await database.getRestoreInfo();
const [data] = await database.get();
console.log(
  `Database ${restoreInfo.backupInfo.sourceDatabase} was restored ` +
    `to ${databaseId} from backup ${restoreInfo.backupInfo.backup} ` +
    `using encryption key ${data.metadata.encryptionConfig.kmsKeyName}.`
);

PHP

use Google\Cloud\Spanner\Admin\Database\V1\RestoreDatabaseEncryptionConfig;
use Google\Cloud\Spanner\SpannerClient;

/**
 * Restore a database from a backup.
 * Example:
 * ```
 * restore_backup_with_encryption_key($instanceId, $databaseId, $backupId, $kmsKeyName);
 * ```
 * @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($instanceId, $databaseId, $backupId, $kmsKeyName)
{
    $spanner = new SpannerClient();
    $instance = $spanner->instance($instanceId);
    $database = $instance->database($databaseId);
    $backup = $instance->backup($backupId);

    $operation = $database->restore($backup->name(), [
        'encryptionConfig' => [
            'kmsKeyName' => $kmsKeyName,
            'encryptionType' => RestoreDatabaseEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION
        ]
    ]);
    // Wait for restore operation to complete.
    $operation->pollUntilComplete();

    // Newly created database has restore information.
    $database->reload();
    $restoreInfo = $database->info()['restoreInfo'];
    $sourceDatabase = $restoreInfo['backupInfo']['sourceDatabase'];
    $sourceBackup = $restoreInfo['backupInfo']['backup'];
    $encryptionConfig = $database->info()['encryptionConfig'];

    printf(
        "Database %s restored from backup %s using encryption key %s" . PHP_EOL,
        $sourceDatabase, $sourceBackup, $encryptionConfig['kmsKeyName']);
}

Python

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

    spanner_client = spanner.Client()
    instance = spanner_client.instance(instance_id)

    # Start restoring an existing backup to a new database.
    backup = instance.backup(backup_id)
    encryption_config = {
        'encryption_type': RestoreDatabaseEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION,
        'kms_key_name': kms_key_name,
    }
    new_database = instance.database(new_database_id, encryption_config=encryption_config)
    operation = new_database.restore(backup)

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

    # Newly created database has restore information.
    new_database.reload()
    restore_info = new_database.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,
            new_database.encryption_config.kms_key_name,
        )
    )

Ruby

# 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"

spanner  = Google::Cloud::Spanner.new project: project_id
instance = spanner.instance instance_id

backup = instance.backup backup_id

encryption_config = {
  encryption_type: :CUSTOMER_MANAGED_ENCRYPTION,
  kms_key_name: kms_key_name
}
job = backup.restore database_id, encryption_config: encryption_config

puts "Waiting for restore backup operation to complete"

job.wait_until_done!
database = job.database
restore_info = database.restore_info
puts "Database #{restore_info.backup_info.source_database_id} was restored to #{database.database_id} from backup #{restore_info.backup_info.backup_id} using encryption key #{database.encryption_config.kms_key_name}"

Audit-Logs für den Cloud KMS-Schlüssel aufrufen

  1. Logging für die Cloud KMS API in Ihrem Projekt muss aktiviert sein .

  2. Rufen Sie in der Cloud Console die Loganzeige auf.

    Zur Cloud Console

  3. Beschränken Sie die Logeinträge auf Ihren Cloud KMS-Schlüssel, indem Sie dem Query Builder die folgenden Zeilen hinzufügen:

    resource.type="cloudkms_cryptokey"
    resource.labels.location="my-kms-key-location"
    resource.labels.key_ring_id="my-kms-key-ring"
    resource.labels.crypto_key_id="my-kms-key"
    
  4. Bei normalen Vorgängen werden Ver- und Entschlüsselungsaktionen mit dem Schweregrad INFO protokolliert. Diese Einträge werden als Zonen in Ihrer Cloud Spanner-Instanz protokolliert, die den Cloud KMS-Schlüssel etwa alle fünf Minuten abfragen.

  5. Wenn Cloud Spanner nicht auf den Schlüssel zugreifen kann, werden die Vorgänge als ERROR protokolliert.