Secure a database with customer-managed encryption keys (CMEK)

This page describes how to use manually-created customer-managed encryption keys(CMEK) for Spanner.

To learn more about CMEK, see theCustomer-managed encryption keys (CMEK) overview.

Create a CMEK-enabled database

  1. Create a key in Cloud Key Management Service (Cloud KMS). You can use thefollowing key types that have differentprotection levels in Spanner:

    The key must be in the same location as your Spannerinstance. For example, if your Spanner instance configurationis inus-west1, then yourCloud KMS key ring locationmust also beus-west1.

    Not every Spannermulti-region instance configurationhas a corresponding Cloud KMS key ring location. ForSpanner databases incustom, dual-region, or multi-regioninstance configurations,you can use multiple regional (single-region) Cloud KMS keys toprotect your database. For example:

    • If your Spanner database is in the multi-region instanceconfigurationnam14, then you can create Cloud KMS keys inus-east4,northamerica-northeast1, andus-east1.
    • If your database is in a custom instance configuration that usesnam3as the base instance configuration with an additional read-only replica inus-central2, then you can create Cloud KMS keys inus-east4,us-east1,us-central1, andus-central2.
    Note: Protecting a CMEK database with a mix of Cloud KMSmulti-region and single-region keys is not supported.

    Optional: To see a list of the replica locations in yourSpanner instance configuration, use thegcloud spanner instances get-locationscommand:

    gcloudspannerinstancesget-locations<var>INSTANCE_ID</var>

    For more information, see the following resources:

  2. Grant Spanner access to the key.

    1. In Cloud Shell, create and display the service agent, or display itif the account already exists:

      gcloudbetaservicesidentitycreate--service=spanner.googleapis.com\--project=PROJECT_ID

      If you're prompted to install thegcloud Beta Commandscomponent, typeY. After installation, the command is automaticallyrestarted.

      Thegcloud services identitycommand creates or gets theservice agent thatSpanner can use to access the Cloud KMS key onyour behalf.

      The service account ID is formatted like an email address:

      Service identity created: service-xxx@gcp-sa-spanner.iam.gserviceaccount.com
    2. Grant theCloud KMS CryptoKey Encrypter/Decrypter(cloudkms.cryptoKeyEncrypterDecrypter)role to the service account for each region (--location) in yourSpanner instance configuration. To do so, run thegcloud kms keys add-iam-policybindingcommand:

      gcloudkmskeysadd-iam-policy-bindingKMS_KEY\--locationKMS_KEY_LOCATION\--keyringKMS_KEY_RING\--project=PROJECT_ID\--memberserviceAccount:service-xxx@gcp-sa-spanner.iam.gserviceaccount.com\--roleroles/cloudkms.cryptoKeyEncrypterDecrypter

      Here's an example output:

      Updated IAM policy for key [KMS_KEY]

      If you're using multiple Cloud KMS keys to protect yourdatabase, run thegcloud kms keys add-iam-policybinding command forall the your keys.

      This role ensures that the service account has permission to bothencrypt and decrypt with the Cloud KMS key. For moreinformation, seeCloud KMS permissions and roles.

  3. Create the database and specify your Cloud KMS key.

Note: You can't use the Google Cloud console to create a database in acustom, dual-region, or multi-region instance configuration that uses multipleCloud KMS keys. You must use the gcloud CLI or clientlibraries to do so.

Console

Use the console to create databases in regional instance configurations.

  1. In the Google Cloud console, go to theInstances page.

    Go to Spanner Instances

  2. Click the instance where you want to create a database.

  3. ClickCreate database and fill out the required fields.

  4. ClickShow encryption options.

  5. SelectCloud KMS key.

  6. Select a key from the drop-down list.

    The list of keys is limited to the current Google Cloud project.To use a key from a different Google Cloud project, create thedatabase using gcloud CLI instead of theGoogle Cloud console.

    Once the database is created, you can verify that the database isCMEK-enabled by viewing theDatabase overview page.

    Screenshot that shows the encryption type and key of a database

gcloud

To create a CMEK-enabled database in a regional, custom, or multi-regioninstance configuration, run thegcloud spanner databases createcommand:

gcloudspannerdatabasescreateDATABASE\--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...]

To verify that a database is CMEK-enabled, run thegcloud spanner databases describecommand:

gcloudspannerdatabasesdescribeDATABASE\--project=SPANNER_PROJECT_ID\--instance=INSTANCE_ID

CMEK-enabled databases include a field forencryptionConfig, as shown in thefollowing example output:

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-dbstate: READY

Client libraries

C#

To create a CMEK-enabled database in a regional instance configuration:

usingGoogle.Cloud.Spanner.Admin.Database.V1;usingGoogle.Cloud.Spanner.Common.V1;usingSystem;usingSystem.Threading.Tasks;publicclassCreateDatabaseWithEncryptionKeyAsyncSample{publicasyncTask<Database>CreateDatabaseWithEncryptionKeyAsync(stringprojectId,stringinstanceId,stringdatabaseId,CryptoKeyNamekmsKeyName){// Create a DatabaseAdminClient instance that can be used to execute a// CreateDatabaseRequest with custom encryption configuration options.DatabaseAdminClientdatabaseAdminClient=DatabaseAdminClient.Create();// Define create table statement for table #1.varcreateSingersTable=@"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.varcreateAlbumsTable=@"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.varrequest=newCreateDatabaseRequest{ParentAsInstanceName=InstanceName.FromProjectInstance(projectId,instanceId),CreateStatement=$"CREATE DATABASE `{databaseId}`",ExtraStatements={createSingersTable,createAlbumsTable},EncryptionConfig=newEncryptionConfig{KmsKeyNameAsCryptoKeyName=kmsKeyName,},};varoperation=awaitdatabaseAdminClient.CreateDatabaseAsync(request);// Wait until the operation has finished.Console.WriteLine("Waiting for the operation to finish.");varcompletedResponse=awaitoperation.PollUntilCompletedAsync();if(completedResponse.IsFaulted){Console.WriteLine($"Error while creating database: {completedResponse.Exception}");throwcompletedResponse.Exception;}vardatabase=completedResponse.Result;Console.WriteLine($"Database {database.Name} created with encryption key {database.EncryptionConfig.KmsKeyName}");returndatabase;}}

To create a CMEK-enabled database in a multi-region instance configuration:

usingGoogle.Cloud.Spanner.Admin.Database.V1;usingGoogle.Cloud.Spanner.Common.V1;usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassCreateDatabaseWithMultiRegionEncryptionAsyncSample{publicasyncTask<Database>CreateDatabaseWithMultiRegionEncryptionAsync(stringprojectId,stringinstanceId,stringdatabaseId,IEnumerable<CryptoKeyName>kmsKeyNames){// Create a DatabaseAdminClient instance that can be used to execute a// CreateDatabaseRequest with custom encryption configuration options.DatabaseAdminClientdatabaseAdminClient=DatabaseAdminClient.Create();// Define create table statement for table #1.varcreateSingersTable=@"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.varcreateAlbumsTable=@"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.varrequest=newCreateDatabaseRequest{ParentAsInstanceName=InstanceName.FromProjectInstance(projectId,instanceId),CreateStatement=$"CREATE DATABASE `{databaseId}`",ExtraStatements={createSingersTable,createAlbumsTable},EncryptionConfig=newEncryptionConfig{KmsKeyNamesAsCryptoKeyNames={kmsKeyNames},},};varoperation=awaitdatabaseAdminClient.CreateDatabaseAsync(request);// Wait until the operation has finished.Console.WriteLine("Waiting for the operation to finish.");varcompletedResponse=awaitoperation.PollUntilCompletedAsync();if(completedResponse.IsFaulted){Console.WriteLine($"Error while creating database: {completedResponse.Exception}");throwcompletedResponse.Exception;}vardatabase=completedResponse.Result;Console.WriteLine($"Database {database.Name} created with encryption keys {string.Join(",", kmsKeyNames)}");returndatabase;}}

C++

To create a CMEK-enabled database in a regional instance configuration:

voidCreateDatabaseWithEncryptionKey(google::cloud::spanner_admin::DatabaseAdminClientclient,std::stringconst&project_id,std::stringconst&instance_id,std::stringconst&database_id,google::cloud::KmsKeyNameconst&encryption_key){google::cloud::spanner::Databasedatabase(project_id,instance_id,database_id);google::spanner::admin::database::v1::CreateDatabaseRequestrequest;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());autodb=client.CreateDatabase(request).get();if(!db)throwstd::move(db).status();std::cout <<"Database " <<db->name() <<" created";std::cout <<" using encryption key " <<encryption_key.FullName();std::cout <<".\n";}

To create a CMEK-enabled database in a multi-region instance configuration:

voidCreateDatabaseWithMRCMEK(google::cloud::spanner_admin::DatabaseAdminClientclient,std::stringconst&project_id,std::stringconst&instance_id,std::stringconst&database_id,std::vector<google::cloud::KmsKeyName>const&encryption_keys){google::cloud::spanner::Databasedatabase(project_id,instance_id,database_id);google::spanner::admin::database::v1::CreateDatabaseRequestrequest;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::KmsKeyNameconst&encryption_key:encryption_keys){request.mutable_encryption_config()->add_kms_key_names(encryption_key.FullName());}autodb=client.CreateDatabase(request).get();if(!db)throwstd::move(db).status();std::cout <<"Database " <<db->name() <<" created";PrintKmsKeys(encryption_keys);}

Go

To create a CMEK-enabled database in a regional instance configuration:

import("context""fmt""io""regexp"database"cloud.google.com/go/spanner/admin/database/apiv1"adminpb"cloud.google.com/go/spanner/admin/database/apiv1/databasepb")funccreateDatabaseWithCustomerManagedEncryptionKey(ctxcontext.Context,wio.Writer,db,kmsKeyNamestring)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)ifmatches==nil||len(matches)!=3{returnfmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey: invalid database id %q",db)}instanceName:=matches[1]databaseId:=matches[2]adminClient,err:=database.NewDatabaseAdminClient(ctx)iferr!=nil{returnfmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey.NewDatabaseAdminClient: %w",err)}deferadminClient.Close()// Create a database with tables using a Customer Managed Encryption Keyreq:=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)iferr!=nil{returnfmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey.CreateDatabase: %w",err)}dbObj,err:=op.Wait(ctx)iferr!=nil{returnfmt.Errorf("createDatabaseWithCustomerManagedEncryptionKey.Wait: %w",err)}fmt.Fprintf(w,"Created database [%s] using encryption key %q\n",dbObj.Name,dbObj.EncryptionConfig.KmsKeyName)returnnil}

To create a CMEK-enabled database in a multi-region instance configuration:

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.funccreateDatabaseWithCustomerManagedMultiRegionEncryptionKey(ctxcontext.Context,wio.Writer,projectID,instanceID,databaseIDstring,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)iferr!=nil{returnfmt.Errorf("createDatabaseWithCustomerManagedMultiRegionEncryptionKey.NewDatabaseAdminClient: %w",err)}deferadminClient.Close()// Create a database with tables using a Customer Managed Multi-Region Encryption Keyreq:=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)iferr!=nil{returnfmt.Errorf("createDatabaseWithCustomerManagedMultiRegionEncryptionKey.CreateDatabase: %w",err)}dbObj,err:=op.Wait(ctx)iferr!=nil{returnfmt.Errorf("createDatabaseWithCustomerManagedMultiRegionEncryptionKey.Wait: %w",err)}fmt.Fprintf(w,"Created database [%s] using multi-region encryption keys %q\n",dbObj.Name,dbObj.EncryptionConfig.GetKmsKeyNames())returnnil}

Java

To create a CMEK-enabled database in a regional instance configuration:

importcom.google.cloud.spanner.Spanner;importcom.google.cloud.spanner.SpannerExceptionFactory;importcom.google.cloud.spanner.SpannerOptions;importcom.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;importcom.google.common.collect.ImmutableList;importcom.google.spanner.admin.database.v1.CreateDatabaseRequest;importcom.google.spanner.admin.database.v1.Database;importcom.google.spanner.admin.database.v1.EncryptionConfig;importcom.google.spanner.admin.database.v1.InstanceName;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.TimeoutException;publicclassCreateDatabaseWithEncryptionKey{staticvoidcreateDatabaseWithEncryptionKey(){// TODO(developer): Replace these variables before running the sample.StringprojectId="my-project";StringinstanceId="my-instance";StringdatabaseId="my-database";StringkmsKeyName="projects/"+projectId+"/locations/<location>/keyRings/<keyRing>/cryptoKeys/<keyId>";try(Spannerspanner=SpannerOptions.newBuilder().setProjectId(projectId).build().getService();DatabaseAdminClientadminClient=spanner.createDatabaseAdminClient()){createDatabaseWithEncryptionKey(adminClient,projectId,instanceId,databaseId,kmsKeyName);}}staticvoidcreateDatabaseWithEncryptionKey(DatabaseAdminClientadminClient,StringprojectId,StringinstanceId,StringdatabaseId,StringkmsKeyName){InstanceNameinstanceName=InstanceName.of(projectId,instanceId);CreateDatabaseRequestrequest=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...");DatabasecreatedDatabase=adminClient.createDatabaseAsync(request).get(120,TimeUnit.SECONDS);System.out.printf("Database %s created with encryption key %s%n",createdDatabase.getName(),createdDatabase.getEncryptionConfig().getKmsKeyName());}catch(ExecutionExceptione){// If the operation failed during execution, expose the cause.throwSpannerExceptionFactory.asSpannerException(e.getCause());}catch(InterruptedExceptione){// Throw when a thread is waiting, sleeping, or otherwise occupied,// and the thread is interrupted, either before or during the activity.throwSpannerExceptionFactory.propagateInterrupt(e);}catch(TimeoutExceptione){// If the operation timed out propagates the timeoutthrowSpannerExceptionFactory.propagateTimeout(e);}}}

To create a CMEK-enabled database in a multi-region instance configuration:

importcom.google.cloud.spanner.Spanner;importcom.google.cloud.spanner.SpannerExceptionFactory;importcom.google.cloud.spanner.SpannerOptions;importcom.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;importcom.google.common.collect.ImmutableList;importcom.google.spanner.admin.database.v1.CreateDatabaseRequest;importcom.google.spanner.admin.database.v1.Database;importcom.google.spanner.admin.database.v1.EncryptionConfig;importcom.google.spanner.admin.database.v1.InstanceName;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.TimeoutException;publicclassCreateDatabaseWithMultiRegionEncryptionKey{staticvoidcreateDatabaseWithEncryptionKey(){// TODO(developer): Replace these variables before running the sample.StringprojectId="my-project";StringinstanceId="my-instance";StringdatabaseId="my-database";String[]kmsKeyNames=newString[]{"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(Spannerspanner=SpannerOptions.newBuilder().setProjectId(projectId).build().getService();DatabaseAdminClientadminClient=spanner.createDatabaseAdminClient()){createDatabaseWithMultiRegionEncryptionKey(adminClient,projectId,instanceId,databaseId,kmsKeyNames);}}staticvoidcreateDatabaseWithMultiRegionEncryptionKey(DatabaseAdminClientadminClient,StringprojectId,StringinstanceId,StringdatabaseId,String[]kmsKeyNames){InstanceNameinstanceName=InstanceName.of(projectId,instanceId);CreateDatabaseRequestrequest=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...");DatabasecreatedDatabase=adminClient.createDatabaseAsync(request).get(120,TimeUnit.SECONDS);System.out.printf("Database %s created with encryption keys %s%n",createdDatabase.getName(),createdDatabase.getEncryptionConfig().getKmsKeyNamesList());}catch(ExecutionExceptione){// If the operation failed during execution, expose the cause.throwSpannerExceptionFactory.asSpannerException(e.getCause());}catch(InterruptedExceptione){// Throw when a thread is waiting, sleeping, or otherwise occupied,// and the thread is interrupted, either before or during the activity.throwSpannerExceptionFactory.propagateInterrupt(e);}catch(TimeoutExceptione){// If the operation timed out propagates the timeoutthrowSpannerExceptionFactory.propagateTimeout(e);}}}

Note: The old client library interface code samples for Java are archived inGitHub.

Node.js

To create a CMEK-enabled database in a regional instance configuration:

// Imports the Google Cloud client libraryconst{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 clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner Database Admin Client objectconstdatabaseAdminClient=spanner.getDatabaseAdminClient();// Creates a databaseconst[operation]=awaitdatabaseAdminClient.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...`);awaitoperation.promise();console.log(`Created database${databaseId} on instance${instanceId}.`);// Get encryption keyconst[metadata]=awaitdatabaseAdminClient.getDatabase({name:databaseAdminClient.databasePath(projectId,instanceId,databaseId),});console.log(`Database encrypted with key${metadata.encryptionConfig.kmsKeyName}.`,);

To create a CMEK-enabled database in a multi-region instance configuration:

/** * 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 libraryconst{Spanner,protos}=require('@google-cloud/spanner');// creates a clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner Database Admin Client objectconstdatabaseAdminClient=spanner.getDatabaseAdminClient();asyncfunctioncreateDatabaseWithMultipleKmsKeys(){// Creates a databaseconst[operation]=awaitdatabaseAdminClient.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...`);awaitoperation.promise();console.log(`Created database${databaseId} on instance${instanceId}.`);// Get encryption keyconst[metadata]=awaitdatabaseAdminClient.getDatabase({name:databaseAdminClient.databasePath(projectId,instanceId,databaseId),});console.log(`Database encrypted with keys${metadata.encryptionConfig.kmsKeyNames}.`,);}createDatabaseWithMultipleKmsKeys();

Note: The old client library interface code samples for Node.js are archived inGitHub.

PHP

To create a CMEK-enabled database in a regional instance configuration:

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

To create a CMEK-enabled database in a multi-region instance configuration:

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

Note: The old client library interface code samples for PHP are archived inGitHub.

Python

To create a CMEK-enabled database in a regional instance configuration:

defcreate_database_with_encryption_key(instance_id,database_id,kms_key_name):"""Creates a database with tables using a Customer Managed Encryption Key (CMEK)."""fromgoogle.cloud.spanner_admin_database_v1importEncryptionConfigfromgoogle.cloud.spanner_admin_database_v1.typesimportspanner_database_adminspanner_client=spanner.Client()database_admin_api=spanner_client.database_admin_apirequest=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))

To create a CMEK-enabled database in a multi-region instance configuration:

defcreate_database_with_multiple_kms_keys(instance_id,database_id,kms_key_names):"""Creates a database with tables using multiple KMS keys(CMEK)."""fromgoogle.cloud.spanner_admin_database_v1importEncryptionConfigfromgoogle.cloud.spanner_admin_database_v1.typesimportspanner_database_adminspanner_client=spanner.Client()database_admin_api=spanner_client.database_admin_apirequest=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))

Note: The old client library interface code samples for Python are archived inGitHub.

Ruby

To create a CMEK-enabled database in a regional instance configuration:

# 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_admininstance_path=database_admin_client.instance_pathproject:project_id,instance:instance_iddb_path=database_admin_client.database_pathproject:project_id,instance:instance_id,database:database_idjob=database_admin_client.create_databaseparent: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_databasename:db_pathputs"Database#{database_id} created with encryption key#{database.encryption_config.kms_key_name}"

To create a CMEK-enabled database in a multi-region instance configuration:

# 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_admininstance_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,CREATETABLESingers(SingerIdINT64NOTNULL,FirstNameSTRING(1024),LastNameSTRING(1024),SingerInfoBYTES(MAX))PRIMARYKEY(SingerId)STATEMENT<<~STATEMENTCREATETABLEAlbums(SingerIdINT64NOTNULL,AlbumIdINT64NOTNULL,AlbumTitleSTRING(MAX))PRIMARYKEY(SingerId,AlbumId),INTERLEAVEINPARENTSingersONDELETECASCADESTATEMENT],encryption_config:encryption_config)puts"Waiting for create database operation to complete"job.wait_until_done!database=database_admin_client.get_databasename:db_pathputs"Database#{database_id} created with encryption key "\"#{database.encryption_config.kms_key_names}"

View the key versions in use

The database'sencryption_infofield shows information about key versions.

When a database's key version changes, the change isn't immediately propagatedtoencryption_info. There might be a delay before the change is reflected inthis field.

Console

  1. In the Google Cloud console, go to theInstances page.

    Go to Instances

  2. Click the instance containing the database you want to view.

  3. Click the database.

    Encryption information is displayed on theDatabase details page.

    Screenshot of the encryption information that is displayed on the Database details page.

gcloud

You can get a database'sencryption_info by running thegcloud spanner databases describeorgcloud spanner databases listcommand. For example:

gcloudspannerdatabasesdescribeDATABASE\--project=SPANNER_PROJECT_ID\--instance=INSTANCE_ID

Here's an example output:

name: projects/my-project/instances/test-instance/databases/example-dbencryptionInfo:- 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

Disable the key

Warning: We strongly recommend against disabling only a subset of keys in aCMEK-enabled database that uses multiple keys. It might cause uncertainbehavior. It's better to disable all keys in the database.
  1. Disable the key version(s) that are in use by followingthese instructions for each key version.

  2. Wait for the change to take effect. Disabling a key can takeup to three hours to propagate.

  3. To confirm that the database is no longer accessible, execute a query inthe CMEK-disabled database:

    gcloudspannerdatabasesexecute-sqlDATABASE\--project=SPANNER_PROJECT_ID\--instance=INSTANCE_ID\--sql='SELECT * FROM Users'

    The following error message appears:KMS key required by the Spanner resource is not accessible.

Enable the key

  1. Enable the key versions that are in use by the database by followingthese instructions for each keyversion.

  2. Wait for the change to take effect. Enabling a key can take up to threehours to propagate.

  3. To confirm that the database is no longer accessible, execute a query inthe CMEK-enabled database:

    gcloudspannerdatabasesexecute-sqlDATABASE\--project=SPANNER_PROJECT_ID\--instance=INSTANCE_ID\--sql='SELECT * FROM Users'

    If the change has taken effect, the command executes successfully.

Back up a database

Note: You can't use the Google Cloud console to specify multipleCloud KMS keys when creating a backup in a custom, dual-region ormulti-region instance configuration. You must use the gcloud CLI orclient libraries to do so.

You can useSpanner backups to createbackups of your databases. By default, Spanner backups createdfrom a database use the sameencryption configurationas the database itself. You can optionally specify a differentencryption configuration for a backup.

Console

Use the console to create backups in regional instance configurations.

  1. In the Google Cloud console, go to theInstances page.

    Go to Spanner Instances

  2. Click the instance name that contains the database that you want to back up.

  3. Click the database.

  4. In the navigation pane, clickBackup/Restore.

  5. In theBackups tab, clickCreate backup.

  6. Enter a backup name and select an expiration date.

  7. Optional: ClickShow encryption options.

    a. If you want to use a different encryption configuration for your backup, click the slider next toUse existing encryption.

    a. SelectCloud KMS key.

    a. Select a key from the drop-down list.

    The list of keys is limited to the current Google Cloud project. To use a key from a different Google Cloud project, create the database using gcloud CLI instead of the Google Cloud console.

  8. ClickCreate.

TheBackups table displays encryption information for each backup.

Screenshot of the Backups table showing the encryption information for each backup

gcloud

To create a CMEK-enabled backup in a regional, custom, or multi-regioninstance configuration, run thegcloud spanner backups createcommand:

gcloudspannerbackupscreateBACKUP\--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

To verify that the backup created is CMEK encrypted:

gcloudspannerbackupsdescribeBACKUP\--project=SPANNER_PROJECT_ID\--instance=INSTANCE_ID

Client libraries

C#

To create a CMEK-enabled backup in a regional instance configuration:

usingGoogle.Cloud.Spanner.Admin.Database.V1;usingGoogle.Cloud.Spanner.Common.V1;usingGoogle.Protobuf.WellKnownTypes;usingSystem;usingSystem.Threading.Tasks;publicclassCreateBackupWithEncryptionKeyAsyncSample{publicasyncTask<Backup>CreateBackupWithEncryptionKeyAsync(stringprojectId,stringinstanceId,stringdatabaseId,stringbackupId,CryptoKeyNamekmsKeyName){// Create a DatabaseAdminClient instance.DatabaseAdminClientdatabaseAdminClient=DatabaseAdminClient.Create();// Create the CreateBackupRequest with encryption configuration.CreateBackupRequestrequest=newCreateBackupRequest{ParentAsInstanceName=InstanceName.FromProjectInstance(projectId,instanceId),BackupId=backupId,Backup=newBackup{DatabaseAsDatabaseName=DatabaseName.FromProjectInstanceDatabase(projectId,instanceId,databaseId),ExpireTime=DateTime.UtcNow.AddDays(14).ToTimestamp(),},EncryptionConfig=newCreateBackupEncryptionConfig{EncryptionType=CreateBackupEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,KmsKeyNameAsCryptoKeyName=kmsKeyName,},};// Execute the CreateBackup request.varoperation=awaitdatabaseAdminClient.CreateBackupAsync(request);Console.WriteLine("Waiting for the operation to finish.");// Poll until the returned long-running operation is complete.varcompletedResponse=awaitoperation.PollUntilCompletedAsync();if(completedResponse.IsFaulted){Console.WriteLine($"Error while creating backup: {completedResponse.Exception}");throwcompletedResponse.Exception;}varbackup=completedResponse.Result;Console.WriteLine($"Backup {backup.Name} of size {backup.SizeBytes} bytes "+$"was created at {backup.CreateTime} "+$"using encryption key {kmsKeyName}");returnbackup;}}

To create a CMEK-enabled backup in a multi-region instance configuration:

usingGoogle.Cloud.Spanner.Admin.Database.V1;usingGoogle.Cloud.Spanner.Common.V1;usingGoogle.Protobuf.WellKnownTypes;usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassCreateBackupWithMultiRegionEncryptionAsyncSample{publicasyncTask<Backup>CreateBackupWithMultiRegionEncryptionAsync(stringprojectId,stringinstanceId,stringdatabaseId,stringbackupId,IEnumerable<CryptoKeyName>kmsKeyNames){// Create a DatabaseAdminClient instance.DatabaseAdminClientdatabaseAdminClient=DatabaseAdminClient.Create();// Create the CreateBackupRequest with encryption configuration.CreateBackupRequestrequest=newCreateBackupRequest{ParentAsInstanceName=InstanceName.FromProjectInstance(projectId,instanceId),BackupId=backupId,Backup=newBackup{DatabaseAsDatabaseName=DatabaseName.FromProjectInstanceDatabase(projectId,instanceId,databaseId),ExpireTime=DateTime.UtcNow.AddDays(14).ToTimestamp(),},EncryptionConfig=newCreateBackupEncryptionConfig{EncryptionType=CreateBackupEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,KmsKeyNamesAsCryptoKeyNames={kmsKeyNames},},};// Execute the CreateBackup request.varoperation=awaitdatabaseAdminClient.CreateBackupAsync(request);Console.WriteLine("Waiting for the operation to finish.");// Poll until the returned long-running operation is complete.varcompletedResponse=awaitoperation.PollUntilCompletedAsync();if(completedResponse.IsFaulted){Console.WriteLine($"Error while creating backup: {completedResponse.Exception}");throwcompletedResponse.Exception;}varbackup=completedResponse.Result;Console.WriteLine($"Backup {backup.Name} of size {backup.SizeBytes} bytes was created with encryption keys {string.Join(",", kmsKeyNames)} at {backup.CreateTime}");returnbackup;}}

C++

To create a CMEK-enabled backup in a regional instance configuration:

voidCreateBackupWithEncryptionKey(google::cloud::spanner_admin::DatabaseAdminClientclient,std::stringconst&project_id,std::stringconst&instance_id,std::stringconst&database_id,std::stringconst&backup_id,google::cloud::spanner::Timestampexpire_time,google::cloud::spanner::Timestampversion_time,google::cloud::KmsKeyNameconst&encryption_key){google::cloud::spanner::Databasedatabase(project_id,instance_id,database_id);google::spanner::admin::database::v1::CreateBackupRequestrequest;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());autobackup=client.CreateBackup(request).get();if(!backup)throwstd::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";}

To create a CMEK-enabled backup in a multi-region instance configuration:

voidCreateBackupWithMRCMEK(google::cloud::spanner_admin::DatabaseAdminClientclient,BackupIdentifierdst,std::stringconst&database_id,google::cloud::spanner::Timestampexpire_time,google::cloud::spanner::Timestampversion_time,std::vector<google::cloud::KmsKeyName>const&encryption_keys){google::cloud::spanner::Databasedatabase(dst.project_id,dst.instance_id,database_id);google::spanner::admin::database::v1::CreateBackupRequestrequest;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::KmsKeyNameconst&encryption_key:encryption_keys){request.mutable_encryption_config()->add_kms_key_names(encryption_key.FullName());}autobackup=client.CreateBackup(request).get();if(!backup)throwstd::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

To create a CMEK-enabled backup in a regional instance configuration:

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")funccreateBackupWithCustomerManagedEncryptionKey(ctxcontext.Context,wio.Writer,db,backupID,kmsKeyNamestring)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)ifmatches==nil||len(matches)!=3{returnfmt.Errorf("createBackupWithCustomerManagedEncryptionKey: invalid database id %q",db)}instanceName:=matches[1]adminClient,err:=database.NewDatabaseAdminClient(ctx)iferr!=nil{returnfmt.Errorf("createBackupWithCustomerManagedEncryptionKey.NewDatabaseAdminClient: %w",err)}deferadminClient.Close()expireTime:=time.Now().AddDate(0,0,14)// Create a backup for a database using a Customer Managed Encryption Keyreq:=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)iferr!=nil{returnfmt.Errorf("createBackupWithCustomerManagedEncryptionKey.CreateBackup: %w",err)}// Wait for backup operation to complete.backup,err:=op.Wait(ctx)iferr!=nil{returnfmt.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)returnnil}

To create a CMEK-enabled backup in a multi-region instance configuration:

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.funccreateBackupWithCustomerManagedMultiRegionEncryptionKey(ctxcontext.Context,wio.Writer,projectID,instanceID,databaseID,backupIDstring,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)iferr!=nil{returnfmt.Errorf("createBackupWithCustomerManagedMultiRegionEncryptionKey.NewDatabaseAdminClient: %w",err)}deferadminClient.Close()expireTime:=time.Now().AddDate(0,0,14)// Create a backup for a database using a Customer Managed Encryption Keyreq:=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)iferr!=nil{returnfmt.Errorf("createBackupWithCustomerManagedMultiRegionEncryptionKey.CreateBackup: %w",err)}// Wait for backup operation to complete.backup,err:=op.Wait(ctx)iferr!=nil{returnfmt.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)returnnil}

Java

To create a CMEK-enabled backup in a regional instance configuration:

importcom.google.cloud.spanner.Spanner;importcom.google.cloud.spanner.SpannerExceptionFactory;importcom.google.cloud.spanner.SpannerOptions;importcom.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;importcom.google.protobuf.Timestamp;importcom.google.spanner.admin.database.v1.Backup;importcom.google.spanner.admin.database.v1.BackupName;importcom.google.spanner.admin.database.v1.CreateBackupEncryptionConfig;importcom.google.spanner.admin.database.v1.CreateBackupEncryptionConfig.EncryptionType;importcom.google.spanner.admin.database.v1.CreateBackupRequest;importcom.google.spanner.admin.database.v1.DatabaseName;importcom.google.spanner.admin.database.v1.InstanceName;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.TimeoutException;importorg.threeten.bp.LocalDateTime;importorg.threeten.bp.OffsetDateTime;publicclassCreateBackupWithEncryptionKey{staticvoidcreateBackupWithEncryptionKey(){// TODO(developer): Replace these variables before running the sample.StringprojectId="my-project";StringinstanceId="my-instance";StringdatabaseId="my-database";StringbackupId="my-backup";StringkmsKeyName="projects/"+projectId+"/locations/<location>/keyRings/<keyRing>/cryptoKeys/<keyId>";try(Spannerspanner=SpannerOptions.newBuilder().setProjectId(projectId).build().getService();DatabaseAdminClientadminClient=spanner.createDatabaseAdminClient()){createBackupWithEncryptionKey(adminClient,projectId,instanceId,databaseId,backupId,kmsKeyName);}}staticVoidcreateBackupWithEncryptionKey(DatabaseAdminClientadminClient,StringprojectId,StringinstanceId,StringdatabaseId,StringbackupId,StringkmsKeyName){// Set expire time to 14 days from now.finalTimestampexpireTime=Timestamp.newBuilder().setSeconds(TimeUnit.MILLISECONDS.toSeconds((System.currentTimeMillis()+TimeUnit.DAYS.toMillis(14)))).build();finalBackupNamebackupName=BackupName.of(projectId,instanceId,backupId);Backupbackup=Backup.newBuilder().setName(backupName.toString()).setDatabase(DatabaseName.of(projectId,instanceId,databaseId).toString()).setExpireTime(expireTime).build();finalCreateBackupRequestrequest=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(ExecutionExceptione){// If the operation failed during execution, expose the cause.throwSpannerExceptionFactory.asSpannerException(e.getCause());}catch(InterruptedExceptione){// Throw when a thread is waiting, sleeping, or otherwise occupied,// and the thread is interrupted, either before or during the activity.throwSpannerExceptionFactory.propagateInterrupt(e);}catch(TimeoutExceptione){// If the operation timed out propagates the timeoutthrowSpannerExceptionFactory.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);returnnull;}}

To create a CMEK-enabled backup in a multi-region instance configuration:

importcom.google.cloud.spanner.Spanner;importcom.google.cloud.spanner.SpannerExceptionFactory;importcom.google.cloud.spanner.SpannerOptions;importcom.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;importcom.google.common.collect.ImmutableList;importcom.google.protobuf.Timestamp;importcom.google.spanner.admin.database.v1.Backup;importcom.google.spanner.admin.database.v1.BackupName;importcom.google.spanner.admin.database.v1.CreateBackupEncryptionConfig;importcom.google.spanner.admin.database.v1.CreateBackupEncryptionConfig.EncryptionType;importcom.google.spanner.admin.database.v1.CreateBackupRequest;importcom.google.spanner.admin.database.v1.DatabaseName;importcom.google.spanner.admin.database.v1.InstanceName;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.TimeoutException;importorg.threeten.bp.LocalDateTime;importorg.threeten.bp.OffsetDateTime;publicclassCreateBackupWithMultiRegionEncryptionKey{staticvoidcreateBackupWithMultiRegionEncryptionKey(){// TODO(developer): Replace these variables before running the sample.StringprojectId="my-project";StringinstanceId="my-instance";StringdatabaseId="my-database";StringbackupId="my-backup";String[]kmsKeyNames=newString[]{"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(Spannerspanner=SpannerOptions.newBuilder().setProjectId(projectId).build().getService();DatabaseAdminClientadminClient=spanner.createDatabaseAdminClient()){createBackupWithMultiRegionEncryptionKey(adminClient,projectId,instanceId,databaseId,backupId,kmsKeyNames);}}staticVoidcreateBackupWithMultiRegionEncryptionKey(DatabaseAdminClientadminClient,StringprojectId,StringinstanceId,StringdatabaseId,StringbackupId,String[]kmsKeyNames){// Set expire time to 14 days from now.finalTimestampexpireTime=Timestamp.newBuilder().setSeconds(TimeUnit.MILLISECONDS.toSeconds((System.currentTimeMillis()+TimeUnit.DAYS.toMillis(14)))).build();finalBackupNamebackupName=BackupName.of(projectId,instanceId,backupId);Backupbackup=Backup.newBuilder().setName(backupName.toString()).setDatabase(DatabaseName.of(projectId,instanceId,databaseId).toString()).setExpireTime(expireTime).build();finalCreateBackupRequestrequest=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(ExecutionExceptione){// If the operation failed during execution, expose the cause.throwSpannerExceptionFactory.asSpannerException(e.getCause());}catch(InterruptedExceptione){// Throw when a thread is waiting, sleeping, or otherwise occupied,// and the thread is interrupted, either before or during the activity.throwSpannerExceptionFactory.propagateInterrupt(e);}catch(TimeoutExceptione){// If the operation timed out propagates the timeoutthrowSpannerExceptionFactory.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));returnnull;}}

Note: The old client library interface code samples for Java are archived inGitHub.

Node.js

To create a CMEK-enabled backup in a regional instance configuration:

// Imports the Google Cloud client libraryconst{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 clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner Database Admin Client objectconstdatabaseAdminClient=spanner.getDatabaseAdminClient();// Creates a new backup of the databasetry{console.log(`Creating backup of database${databaseAdminClient.databasePath(projectId,instanceId,databaseId,)}.`,);// Expire backup 14 days in the futureconstexpireTime=Date.now()+1000*60*60*24*14;// Create a backup of the state of the database at the current time.const[operation]=awaitdatabaseAdminClient.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...`,);awaitoperation.promise();// Verify backup is readyconst[backupInfo]=awaitdatabaseAdminClient.getBackup({name:databaseAdminClient.backupPath(projectId,instanceId,backupId),});if(backupInfo.state==='READY'){console.log(`Backup${backupInfo.name} of size `+`${backupInfo.sizeBytes} bytes was created at `+`${newPreciseDate(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();}

To create a CMEK-enabled backup in a multi-region instance configuration:

/** * 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 libraryconst{Spanner,protos}=require('@google-cloud/spanner');const{PreciseDate}=require('@google-cloud/precise-date');// Creates a clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner Database Admin Client objectconstdatabaseAdminClient=spanner.getDatabaseAdminClient();asyncfunctioncreateBackupWithMultipleKmsKeys(){// Creates a new backup of the databasetry{console.log(`Creating backup of database${databaseAdminClient.databasePath(projectId,instanceId,databaseId,)}.`,);// Expire backup 14 days in the futureconstexpireTime=Date.now()+1000*60*60*24*14;// Create a backup of the state of the database at the current time.const[operation]=awaitdatabaseAdminClient.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...`,);awaitoperation.promise();// Verify backup is readyconst[backupInfo]=awaitdatabaseAdminClient.getBackup({name:databaseAdminClient.backupPath(projectId,instanceId,backupId),});constkmsKeyVersions=backupInfo.encryptionInformation.map(encryptionInfo=>encryptionInfo.kmsKeyVersion).join(', ');if(backupInfo.state==='READY'){console.log(`Backup${backupInfo.name} of size `+`${backupInfo.sizeBytes} bytes was created at `+`${newPreciseDate(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();

Note: The old client library interface code samples for Node.js are archived inGitHub.

PHP

To create a CMEK-enabled backup in a regional instance configuration:

useGoogle\Cloud\Spanner\Admin\Database\V1\Backup;use\Google\Cloud\Spanner\Admin\Database\V1\Backup\State;useGoogle\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;useGoogle\Cloud\Spanner\Admin\Database\V1\CreateBackupEncryptionConfig;useGoogle\Cloud\Spanner\Admin\Database\V1\CreateBackupRequest;useGoogle\Cloud\Spanner\Admin\Database\V1\GetBackupRequest;useGoogle\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. */functioncreate_backup_with_encryption_key(string$projectId,string$instanceId,string$databaseId,string$backupId,string$kmsKeyName):void{$databaseAdminClient=newDatabaseAdminClient();$instanceFullName=DatabaseAdminClient::instanceName($projectId,$instanceId);$databaseFullName=DatabaseAdminClient::databaseName($projectId,$instanceId,$databaseId);$expireTime=newTimestamp();$expir>eTime-setSeconds((new\DateTime('+14 da>ys'))-getTimestamp());$request=newCreateBackupRequest(['par>ent'=$instanceFullName,'backup>_id'=$backupId,'encryption_con>fig'=newCreateBackupEncryptionConfig(['kms_key_n>ame'=$kmsKeyName,'encryption_t>ype'=CreateBackupEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION]),'bac>kup'=newBackup(['datab>ase'=$databaseFullName,'expire_t>ime'=$expireTime])]);$operation=$databaseAdminC>lient-createBackup($request);print('Waiting for operation to complete...'.PHP_EOL);$oper>ation-pollUntilComplete();$request=newGetBackupRequest();$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);}}

To create a CMEK-enabled backup in a multi-region instance configuration:

useGoogle\Cloud\Spanner\Admin\Database\V1\Backup;use\Google\Cloud\Spanner\Admin\Database\V1\Backup\State;useGoogle\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;useGoogle\Cloud\Spanner\Admin\Database\V1\CreateBackupEncryptionConfig;useGoogle\Cloud\Spanner\Admin\Database\V1\CreateBackupRequest;useGoogle\Cloud\Spanner\Admin\Database\V1\GetBackupRequest;useGoogle\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. */functioncreate_backup_with_mr_cmek(string$projectId,string$instanceId,string$databaseId,string$backupId,array$kmsKeyNames):void{$databaseAdminClient=newDatabaseAdminClient();$instanceFullName=DatabaseAdminClient::instanceName($projectId,$instanceId);$databaseFullName=DatabaseAdminClient::databaseName($projectId,$instanceId,$databaseId);$expireTime=newTimestamp();$expir>eTime-setSeconds((new\DateTime('+14 da>ys'))-getTimestamp());$request=newCreateBackupRequest(['par>ent'=$instanceFullName,'backup>_id'=$backupId,'encryption_con>fig'=newCreateBackupEncryptionConfig(['kms_key_na>mes'=$kmsKeyNames,'encryption_t>ype'=CreateBackupEncryptionConfig\EncryptionType::CUSTOMER_MANAGED_ENCRYPTION]),'bac>kup'=newBackup(['datab>ase'=$databaseFullName,'expire_t>ime'=$expireTime])]);$operation=$databaseAdminC>lient-createBackup($request);print('Waiting for operation to complete...'.PHP_EOL);$oper>ation-pollUntilComplete();$request=newGetBackupRequest();$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);}}

Note: The old client library interface code samples for PHP are archived inGitHub.

Python

To create a CMEK-enabled backup in a regional instance configuration:

defcreate_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)."""fromgoogle.cloud.spanner_admin_database_v1importCreateBackupEncryptionConfigfromgoogle.cloud.spanner_admin_database_v1.typesimportbackupasbackup_pbspanner_client=spanner.Client()database_admin_api=spanner_client.database_admin_api# Create a backupexpire_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.assertbackup.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))

To create a CMEK-enabled backup in a multi-region instance configuration:

defcreate_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)."""fromgoogle.cloud.spanner_admin_database_v1importCreateBackupEncryptionConfigfromgoogle.cloud.spanner_admin_database_v1.typesimportbackupasbackup_pbspanner_client=spanner.Client()database_admin_api=spanner_client.database_admin_api# Create a backupexpire_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.assertbackup.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))

Note: The old client library interface code samples for Python are archived inGitHub.

Ruby

To create a CMEK-enabled backup in a regional instance configuration:

# 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_admininstance_path=database_admin_client.instance_pathproject:project_id,instance:instance_iddb_path=database_admin_client.database_pathproject:project_id,instance:instance_id,database:database_idbackup_path=database_admin_client.backup_pathproject:project_id,instance:instance_id,backup:backup_idexpire_time=Time.now+(14*24*3600)# 14 days from nowencryption_config={encryption_type::CUSTOMER_MANAGED_ENCRYPTION,kms_key_name:kms_key_name}job=database_admin_client.create_backupparent:instance_path,backup_id:backup_id,backup:{database:db_path,expire_time:expire_time},encryption_config:encryption_configputs"Backup operation in progress"job.wait_until_done!backup=database_admin_client.get_backupname:backup_pathputs"Backup#{backup_id} of size#{backup.size_bytes} bytes was created at#{backup.create_time} using encryption key#{kms_key_name}"

To create a CMEK-enabled backup in a multi-region instance configuration:

# 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_admininstance_path=database_admin_client.instance_path(project:project_id,instance:instance_id)db_path=database_admin_client.database_pathproject:project_id,instance:instance_id,database:database_idbackup_path=database_admin_client.backup_pathproject:project_id,instance:instance_id,backup:backup_idexpire_time=Time.now+(14*24*3600)# 14 days from nowencryption_config={encryption_type::CUSTOMER_MANAGED_ENCRYPTION,kms_key_names:kms_key_names}job=database_admin_client.create_backupparent:instance_path,backup_id:backup_id,backup:{database:db_path,expire_time:expire_time},encryption_config:encryption_configputs"Backup operation in progress"job.wait_until_done!backup=database_admin_client.get_backupname:backup_pathputs"Backup#{backup_id} of size#{backup.size_bytes} bytes was created "\"at#{backup.create_time} using encryption key#{kms_key_names}"

Copy a backup

Note: You can't use the Google Cloud console to specify multiple keys whencopying a backup in a custom, dual-region, or multi-region instanceconfiguration. You must use the gcloud CLI or client libraries to do so.

You cancopy a backupof your Spanner database from one instance to another instance ina different region or project. By default, a copied backup uses the sameencryption configuration, either Google-managed or customer-managed, asits source backup encryption. You can override this behavior by specifying adifferent encryption configuration when copying the backup. If you want thecopied backup to be encrypted with CMEK when copying across regions, specify theCloud KMS keys corresponding to the destination regions.

Console

Use the console to copy a backup in a regional instance configuration.

  1. In the Google Cloud console, go to theInstances page.

    Go to Spanner Instances

  2. Click the instance name that contains the database that you want to back up.

  3. Click the database.

  4. In the navigation pane, clickBackup/Restore.

  5. In theBackups table, selectActions for your backup and clickCopy.

  6. Fill out the form by choosing a destination instance, providing a name, andselecting an expiration date for the backup copy.

  7. Optional: If you want to use a different encryption configuration for yourbackup, clickShow encryption options.

    a. SelectCloud KMS key.

    a. Select a key from the drop-down list.

    The list of keys is limited to the current Google Cloud project. To use a key from a different Google Cloud project, create the database using gcloud CLI instead of the Google Cloud console.

  8. ClickCopy.

gcloud

To copy a backup, with a new encryption configuration, to a different instancein the same project, run the followinggcloud spanner backups copycommand:

gcloudspannerbackupscopy--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...]

To copy a backup, with a new encryption configuration, to a different instancein a different project, run the followinggcloud spanner backups copycommand:

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

To verify that the copied backup is CMEK encrypted:

gcloudspannerbackupsdescribeBACKUP\--project=SPANNER_PROJECT_ID\--instance=INSTANCE_ID

Client libraries

C#

To copy a CMEK-enabled backup in a multi-region instance configuration:

usingGoogle.Cloud.Spanner.Admin.Database.V1;usingGoogle.Cloud.Spanner.Common.V1;usingGoogle.Protobuf.WellKnownTypes;usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassCopyBackupWithMultiRegionEncryptionAsyncSample{publicasyncTask<Backup>CopyBackupWithMultiRegionEncryptionAsync(stringsourceProjectId,stringsourceInstanceId,stringsourceBackupId,stringtargetProjectId,stringtargetInstanceId,stringtargetBackupId,DateTimeOffsetexpireTime,IEnumerable<CryptoKeyName>kmsKeyNames){DatabaseAdminClientdatabaseAdminClient=DatabaseAdminClient.Create();varrequest=newCopyBackupRequest{SourceBackupAsBackupName=newBackupName(sourceProjectId,sourceInstanceId,sourceBackupId),ParentAsInstanceName=newInstanceName(targetProjectId,targetInstanceId),BackupId=targetBackupId,ExpireTime=Timestamp.FromDateTimeOffset(expireTime),EncryptionConfig=newCopyBackupEncryptionConfig{EncryptionType=CopyBackupEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,KmsKeyNamesAsCryptoKeyNames={kmsKeyNames},}};// Execute the CopyBackup request.varoperation=awaitdatabaseAdminClient.CopyBackupAsync(request);Console.WriteLine("Waiting for the operation to finish.");// Poll until the returned long-running operation is complete.varcompletedResponse=awaitoperation.PollUntilCompletedAsync();if(completedResponse.IsFaulted){Console.WriteLine($"Error while copying backup: {completedResponse.Exception}");throwcompletedResponse.Exception;}Backupbackup=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}");returnbackup;}}

C++

To copy a CMEK-enabled backup in a multi-region instance configuration:

structBackupIdentifier{std::stringproject_id;std::stringinstance_id;std::stringbackup_id;};voidPrintKmsKeys(std::vector<google::cloud::KmsKeyName>const&encryption_keys){std::cout <<" using encryption keys ";for(std::size_ti=0;i <encryption_keys.size();++i){std::cout <<encryption_keys[i].FullName();if(i!=encryption_keys.size()-1){std::cout <<", ";}}std::cout <<".\n";}voidCopyBackupWithMRCMEK(google::cloud::spanner_admin::DatabaseAdminClientclient,BackupIdentifierconst&src,BackupIdentifierconst&dst,google::cloud::spanner::Timestampexpire_time,std::vector<google::cloud::KmsKeyName>const&encryption_keys){google::cloud::spanner::Backupsource(google::cloud::spanner::Instance(src.project_id,src.instance_id),src.backup_id);google::cloud::spanner::Instancedst_in(dst.project_id,dst.instance_id);google::spanner::admin::database::v1::CopyBackupRequestrequest;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::KmsKeyNameconst&encryption_key:encryption_keys){request.mutable_encryption_config()->add_kms_key_names(encryption_key.FullName());}autocopy_backup=client.CopyBackup(request).get();if(!copy_backup)throwstd::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

To copy a CMEK-enabled backup in a multi-region instance configuration:

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.funccopyBackupWithMultiRegionEncryptionKey(wio.Writer,instancePathstring,copyBackupIdstring,sourceBackupPathstring,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)defercancel()// Instantiate database admin client.adminClient,err:=database.NewDatabaseAdminClient(ctx)iferr!=nil{returnfmt.Errorf("database.NewDatabaseAdminClient: %w",err)}deferadminClient.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)iferr!=nil{returnfmt.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)iferr!=nil{returnfmt.Errorf("copyBackup.Wait: %w",err)}// Check if long-running copyBackup operation is completed.if!copyBackupOp.Done(){returnfmt.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))returnnil}

Java

To copy a CMEK-enabled backup in a multi-region instance configuration:

importcom.google.cloud.Timestamp;importcom.google.cloud.spanner.Spanner;importcom.google.cloud.spanner.SpannerException;importcom.google.cloud.spanner.SpannerExceptionFactory;importcom.google.cloud.spanner.SpannerOptions;importcom.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;importcom.google.common.collect.ImmutableList;importcom.google.spanner.admin.database.v1.Backup;importcom.google.spanner.admin.database.v1.BackupName;importcom.google.spanner.admin.database.v1.CopyBackupEncryptionConfig;importcom.google.spanner.admin.database.v1.CopyBackupEncryptionConfig.EncryptionType;importcom.google.spanner.admin.database.v1.CopyBackupRequest;importcom.google.spanner.admin.database.v1.InstanceName;importjava.time.Instant;importjava.time.OffsetDateTime;importjava.time.ZoneId;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.TimeUnit;publicclassCopyBackupWithMultiRegionEncryptionKey{staticvoidcopyBackupWithMultiRegionEncryptionKey(){// TODO(developer): Replace these variables before running the sample.StringprojectId="my-project";StringinstanceId="my-instance";StringsourceBackupId="my-backup";StringdestinationBackupId="my-destination-backup";String[]kmsKeyNames=newString[]{"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(Spannerspanner=SpannerOptions.newBuilder().setProjectId(projectId).build().getService();DatabaseAdminClientdatabaseAdminClient=spanner.createDatabaseAdminClient()){copyBackupWithMultiRegionEncryptionKey(databaseAdminClient,projectId,instanceId,sourceBackupId,destinationBackupId,kmsKeyNames);}}staticvoidcopyBackupWithMultiRegionEncryptionKey(DatabaseAdminClientdatabaseAdminClient,StringprojectId,StringinstanceId,StringsourceBackupId,StringdestinationBackupId,String[]kmsKeyNames){TimestampexpireTime=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+"]...");CopyBackupRequestrequest=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();BackupdestinationBackup;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(ExecutionExceptione){throw(SpannerException)e.getCause();}catch(InterruptedExceptione){throwSpannerExceptionFactory.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

To copy a CMEK-enabled backup in a multi-region instance configuration:

/** * 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 libraryconst{Spanner}=require('@google-cloud/spanner');const{PreciseDate}=require('@google-cloud/precise-date');// Creates a clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner Database Admin Client objectconstdatabaseAdminClient=spanner.getDatabaseAdminClient();asyncfunctionspannerCopyBackupWithMultipleKmsKeys(){// Expire copy backup 14 days in the futureconstexpireTime=Spanner.timestamp(Date.now()+1000*60*60*24*14,).toStruct();// Copy the source backuptry{console.log(`Creating copy of the source backup${sourceBackupPath}.`);const[operation]=awaitdatabaseAdminClient.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...`,);awaitoperation.promise();// Verify the copy backup is readyconst[copyBackup]=awaitdatabaseAdminClient.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 `+`${newPreciseDate(copyBackup.createTime).toISOString()} `+'with version time '+`${newPreciseDate(copyBackup.versionTime).toISOString()}`,);}else{console.error('ERROR: Copy of backup is not ready.');}}catch(err){console.error('ERROR:',err);}}spannerCopyBackupWithMultipleKmsKeys();

PHP

To copy a CMEK-enabled backup in a multi-region instance configuration:

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

To copy a CMEK-enabled backup in a multi-region instance configuration:

defcopy_backup_with_multiple_kms_keys(instance_id,backup_id,source_backup_path,kms_key_names):"""Copies a backup."""fromgoogle.cloud.spanner_admin_database_v1.typesimportbackupasbackup_pbfromgoogle.cloud.spanner_admin_database_v1importCopyBackupEncryptionConfigspanner_client=spanner.Client()database_admin_api=spanner_client.database_admin_apiencryption_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.assertcopy_backup.state==backup_pb.Backup.State.READYprint("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

To copy a CMEK-enabled backup in a multi-region instance configuration:

# 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_admininstance_path=database_admin_client.instance_path(project:project_id,instance:instance_id)backup_path=database_admin_client.backup_pathproject:project_id,instance:instance_id,backup:backup_idsource_backup=database_admin_client.backup_pathproject:project_id,instance:instance_id,backup:source_backup_idexpire_time=Time.now+(14*24*3600)# 14 days from nowencryption_config={encryption_type::CUSTOMER_MANAGED_ENCRYPTION,kms_key_names:kms_key_names}job=database_admin_client.copy_backupparent:instance_path,backup_id:backup_id,source_backup:source_backup,expire_time:expire_time,encryption_config:encryption_configputs"Copy backup operation in progress"job.wait_until_done!backup=database_admin_client.get_backupname:backup_pathputs"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}"

Restore from a backup

Note: You can't use the Google Cloud console to specify multiple keys whenrestoring from a backup in a custom, dual-region, or multi-region instanceconfiguration. You must use the gcloud CLI or client libraries to doso.

You canrestore a backup of aSpanner database into a new database. By default, databases thatare restored from a backup use the sameencryption configurationas the backup itself, but you can override this behavior by specifying adifferent encryption configuration for the restored database. If the backup isprotected by CMEK, the key version that was used to create the backup must beavailable so that it can be decrypted.

Console

Use the console to restore a backup in a regional instance configuration.

  1. In the Google Cloud console, go to theInstances page.

    Go to Spanner Instances

  2. Click the instance containing the database you want to restore.

  3. Click the database.

  4. In the navigation pane, clickBackup/Restore.

  5. In theBackups table, selectActions for your backup and clickRestore.

  6. Select the instance to restore and name the restored database.

  7. Optional: If you want to use a different encryption configuration with yourrestored database, click the slider next toUse existing encryption.

    a. SelectCloud KMS key.

    a. Select a key from the drop-down list.

    The list of keys is limited to the current Google Cloud project. To use a key from a different Google Cloud project, create the database using gcloud CLI instead of the Google Cloud console.

  8. ClickRestore.

gcloud

To restore a backup, with a new encryption configuration, run the followinggcloud spanner databases restorecommand:

gcloudspannerdatabasesrestore--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

To verify that the restored database is CMEK encrypted:

gcloudspannerdatabasesdescribeDATABASE\--project=SPANNER_PROJECT_ID\--instance=INSTANCE_ID

For more information, seeRestore from a backup.

Client libraries

C#

To restore a CMEK-enabled backup in a regional instance configuration:

usingGoogle.Cloud.Spanner.Admin.Database.V1;usingGoogle.Cloud.Spanner.Common.V1;usingSystem;usingSystem.Threading.Tasks;publicclassRestoreDatabaseWithEncryptionAsyncSample{publicasyncTask<Database>RestoreDatabaseWithEncryptionAsync(stringprojectId,stringinstanceId,stringdatabaseId,stringbackupId,CryptoKeyNamekmsKeyName){// Create a DatabaseAdminClient instance.DatabaseAdminClientdatabaseAdminClient=DatabaseAdminClient.Create();// Create the RestoreDatabaseRequest with encryption configuration.RestoreDatabaseRequestrequest=newRestoreDatabaseRequest{ParentAsInstanceName=InstanceName.FromProjectInstance(projectId,instanceId),DatabaseId=databaseId,BackupAsBackupName=BackupName.FromProjectInstanceBackup(projectId,instanceId,backupId),EncryptionConfig=newRestoreDatabaseEncryptionConfig{EncryptionType=RestoreDatabaseEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,KmsKeyNameAsCryptoKeyName=kmsKeyName,}};// Execute the RestoreDatabase request.varoperation=awaitdatabaseAdminClient.RestoreDatabaseAsync(request);Console.WriteLine("Waiting for the operation to finish.");// Poll until the returned long-running operation is complete.varcompletedResponse=awaitoperation.PollUntilCompletedAsync();if(completedResponse.IsFaulted){Console.WriteLine($"Error while restoring database: {completedResponse.Exception}");throwcompletedResponse.Exception;}vardatabase=completedResponse.Result;varrestoreInfo=database.RestoreInfo;Console.WriteLine($"Database {restoreInfo.BackupInfo.SourceDatabase} "+$"restored to {database.Name} "+$"from backup {restoreInfo.BackupInfo.Backup} "+$"using encryption key {database.EncryptionConfig.KmsKeyName}");returndatabase;}}

To restore a CMEK-enabled backup in a multi-region instance configuration:

usingGoogle.Cloud.Spanner.Admin.Database.V1;usingGoogle.Cloud.Spanner.Common.V1;usingSystem;usingSystem.Collections.Generic;usingSystem.Threading.Tasks;publicclassRestoreDatabaseWithMultiRegionEncryptionAsyncSample{publicasyncTask<Database>RestoreDatabaseWithMultiRegionEncryptionAsync(stringprojectId,stringinstanceId,stringdatabaseId,stringbackupId,IEnumerable<CryptoKeyName>kmsKeyNames){// Create a DatabaseAdminClient instance.DatabaseAdminClientdatabaseAdminClient=DatabaseAdminClient.Create();// Create the RestoreDatabaseRequest with encryption configuration.RestoreDatabaseRequestrequest=newRestoreDatabaseRequest{ParentAsInstanceName=InstanceName.FromProjectInstance(projectId,instanceId),DatabaseId=databaseId,BackupAsBackupName=BackupName.FromProjectInstanceBackup(projectId,instanceId,backupId),EncryptionConfig=newRestoreDatabaseEncryptionConfig{EncryptionType=RestoreDatabaseEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,KmsKeyNamesAsCryptoKeyNames={kmsKeyNames},}};// Execute the RestoreDatabase request.varoperation=awaitdatabaseAdminClient.RestoreDatabaseAsync(request);Console.WriteLine("Waiting for the operation to finish.");// Poll until the returned long-running operation is complete.varcompletedResponse=awaitoperation.PollUntilCompletedAsync();if(completedResponse.IsFaulted){Console.WriteLine($"Error while restoring database: {completedResponse.Exception}");throwcompletedResponse.Exception;}vardatabase=completedResponse.Result;varrestoreInfo=database.RestoreInfo;Console.WriteLine($"Database {restoreInfo.BackupInfo.SourceDatabase} restored to {database.Name} from backup {restoreInfo.BackupInfo.Backup} using encryption keys {string.Join(",", kmsKeyNames)}");returndatabase;}}

C++

To restore a CMEK-enabled backup in a regional instance configuration:

voidRestoreDatabaseWithEncryptionKey(google::cloud::spanner_admin::DatabaseAdminClientclient,std::stringconst&project_id,std::stringconst&instance_id,std::stringconst&database_id,std::stringconst&backup_id,google::cloud::KmsKeyNameconst&encryption_key){google::cloud::spanner::Databasedatabase(project_id,instance_id,database_id);google::cloud::spanner::Backupbackup(database.instance(),backup_id);google::spanner::admin::database::v1::RestoreDatabaseRequestrequest;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());autorestored_db=client.RestoreDatabase(request).get();if(!restored_db)throwstd::move(restored_db).status();std::cout <<"Database";if(restored_db->restore_info().source_type()==google::spanner::admin::database::v1::BACKUP){autoconst&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";}

To restore a CMEK-enabled backup in a multi-region instance configuration:

voidRestoreDatabaseWithMRCMEK(google::cloud::spanner_admin::DatabaseAdminClientclient,BackupIdentifierconst&src,std::stringconst&database_id,std::vector<google::cloud::KmsKeyName>const&encryption_keys){google::cloud::spanner::Databasedatabase(src.project_id,src.instance_id,database_id);google::cloud::spanner::Backupbackup(database.instance(),src.backup_id);google::spanner::admin::database::v1::RestoreDatabaseRequestrequest;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::KmsKeyNameconst&encryption_key:encryption_keys){request.mutable_encryption_config()->add_kms_key_names(encryption_key.FullName());}autorestored_db=client.RestoreDatabase(request).get();if(!restored_db)throwstd::move(restored_db).status();std::cout <<"Database";if(restored_db->restore_info().source_type()==google::spanner::admin::database::v1::BACKUP){autoconst&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

To restore a CMEK-enabled backup in a regional instance configuration:

import("context""fmt""io""regexp"database"cloud.google.com/go/spanner/admin/database/apiv1"adminpb"cloud.google.com/go/spanner/admin/database/apiv1/databasepb")funcrestoreBackupWithCustomerManagedEncryptionKey(ctxcontext.Context,wio.Writer,db,backupID,kmsKeyNamestring)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)ifmatches==nil||len(matches)!=3{returnfmt.Errorf("restoreBackupWithCustomerManagedEncryptionKey: invalid database id %q",db)}instanceName:=matches[1]databaseID:=matches[2]backupName:=instanceName+"/backups/"+backupIDadminClient,err:=database.NewDatabaseAdminClient(ctx)iferr!=nil{returnfmt.Errorf("restoreBackupWithCustomerManagedEncryptionKey.NewDatabaseAdminClient: %w",err)}deferadminClient.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,},})iferr!=nil{returnfmt.Errorf("restoreBackupWithCustomerManagedEncryptionKey.RestoreDatabase: %w",err)}// Wait for restore operation to complete.restoredDatabase,err:=restoreOp.Wait(ctx)iferr!=nil{returnfmt.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)returnnil}

To restore a CMEK-enabled backup in a multi-region instance configuration:

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.funcrestoreBackupWithCustomerManagedMultiRegionEncryptionKey(ctxcontext.Context,wio.Writer,instName,databaseIDstring,backupIDstring,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)iferr!=nil{returnfmt.Errorf("restoreBackupWithCustomerManagedMultiRegionEncryptionKey.NewDatabaseAdminClient: %w",err)}deferadminClient.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,},})iferr!=nil{returnfmt.Errorf("restoreBackupWithCustomerManagedMultiRegionEncryptionKey.RestoreDatabase: %w",err)}// Wait for restore operation to complete.restoredDatabase,err:=restoreOp.Wait(ctx)iferr!=nil{returnfmt.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())returnnil}

Java

To restore a CMEK-enabled backup in a regional instance configuration:

import staticcom.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION;importcom.google.cloud.spanner.Spanner;importcom.google.cloud.spanner.SpannerExceptionFactory;importcom.google.cloud.spanner.SpannerOptions;importcom.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;importcom.google.spanner.admin.database.v1.BackupName;importcom.google.spanner.admin.database.v1.Database;importcom.google.spanner.admin.database.v1.InstanceName;importcom.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig;importcom.google.spanner.admin.database.v1.RestoreDatabaseRequest;importjava.util.concurrent.ExecutionException;publicclassRestoreBackupWithEncryptionKey{staticvoidrestoreBackupWithEncryptionKey(){// TODO(developer): Replace these variables before running the sample.StringprojectId="my-project";StringinstanceId="my-instance";StringdatabaseId="my-database";StringbackupId="my-backup";StringkmsKeyName="projects/"+projectId+"/locations/<location>/keyRings/<keyRing>/cryptoKeys/<keyId>";try(Spannerspanner=SpannerOptions.newBuilder().setProjectId(projectId).build().getService();DatabaseAdminClientadminClient=spanner.createDatabaseAdminClient()){restoreBackupWithEncryptionKey(adminClient,projectId,instanceId,backupId,databaseId,kmsKeyName);}}staticVoidrestoreBackupWithEncryptionKey(DatabaseAdminClientadminClient,StringprojectId,StringinstanceId,StringbackupId,StringrestoreId,StringkmsKeyName){RestoreDatabaseRequestrequest=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();Databasedatabase;try{System.out.println("Waiting for operation to complete...");database=adminClient.restoreDatabaseAsync(request).get();;}catch(ExecutionExceptione){// If the operation failed during execution, expose the cause.throwSpannerExceptionFactory.asSpannerException(e.getCause());}catch(InterruptedExceptione){// Throw when a thread is waiting, sleeping, or otherwise occupied,// and the thread is interrupted, either before or during the activity.throwSpannerExceptionFactory.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());returnnull;}}

To restore a CMEK-enabled backup in a multi-region instance configuration:

import staticcom.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION;importcom.google.cloud.spanner.Spanner;importcom.google.cloud.spanner.SpannerExceptionFactory;importcom.google.cloud.spanner.SpannerOptions;importcom.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;importcom.google.common.collect.ImmutableList;importcom.google.spanner.admin.database.v1.BackupName;importcom.google.spanner.admin.database.v1.Database;importcom.google.spanner.admin.database.v1.InstanceName;importcom.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig;importcom.google.spanner.admin.database.v1.RestoreDatabaseRequest;importjava.util.concurrent.ExecutionException;publicclassRestoreBackupWithMultiRegionEncryptionKey{staticvoidrestoreBackupWithMultiRegionEncryptionKey(){// TODO(developer): Replace these variables before running the sample.StringprojectId="my-project";StringinstanceId="my-instance";StringdatabaseId="my-database";StringbackupId="my-backup";String[]kmsKeyNames=newString[]{"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(Spannerspanner=SpannerOptions.newBuilder().setProjectId(projectId).build().getService();DatabaseAdminClientadminClient=spanner.createDatabaseAdminClient()){restoreBackupWithMultiRegionEncryptionKey(adminClient,projectId,instanceId,backupId,databaseId,kmsKeyNames);}}staticVoidrestoreBackupWithMultiRegionEncryptionKey(DatabaseAdminClientadminClient,StringprojectId,StringinstanceId,StringbackupId,StringrestoreId,String[]kmsKeyNames){RestoreDatabaseRequestrequest=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();Databasedatabase;try{System.out.println("Waiting for operation to complete...");database=adminClient.restoreDatabaseAsync(request).get();;}catch(ExecutionExceptione){// If the operation failed during execution, expose the cause.throwSpannerExceptionFactory.asSpannerException(e.getCause());}catch(InterruptedExceptione){// Throw when a thread is waiting, sleeping, or otherwise occupied,// and the thread is interrupted, either before or during the activity.throwSpannerExceptionFactory.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());returnnull;}}

Note: The old client library interface code samples for Java are archived inGitHub.

Node.js

To restore a CMEK-enabled backup in a regional instance configuration:

// Imports the Google Cloud client library and precise date libraryconst{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 clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner Database Admin Client objectconstdatabaseAdminClient=spanner.getDatabaseAdminClient();// Restore the databaseconsole.log(`Restoring database${databaseAdminClient.databasePath(projectId,instanceId,databaseId,)} from backup${backupId}.`,);const[restoreOperation]=awaitdatabaseAdminClient.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 completeconsole.log('Waiting for database restore to complete...');awaitrestoreOperation.promise();console.log('Database restored from backup.');const[metadata]=awaitdatabaseAdminClient.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}.`,);

To restore a CMEK-enabled backup in a multi-region instance configuration:

/** * 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 libraryconst{Spanner}=require('@google-cloud/spanner');// Creates a clientconstspanner=newSpanner({projectId:projectId,});// Gets a reference to a Cloud Spanner Database Admin Client objectconstdatabaseAdminClient=spanner.getDatabaseAdminClient();asyncfunctionrestoreBackupWithMultipleKmsKeys(){// Restore the databaseconsole.log(`Restoring database${databaseAdminClient.databasePath(projectId,instanceId,databaseId,)} from backup${backupId}.`,);const[restoreOperation]=awaitdatabaseAdminClient.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 completeconsole.log('Waiting for database restore to complete...');awaitrestoreOperation.promise();console.log('Database restored from backup.');const[metadata]=awaitdatabaseAdminClient.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();

Note: The old client library interface code samples for Node.js are archived inGitHub.

PHP

To restore a CMEK-enabled backup in a regional instance configuration:

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

To restore a CMEK-enabled backup in a multi-region instance configuration:

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

Note: The old client library interface code samples for PHP are archived inGitHub.

Python

To restore a CMEK-enabled backup in a regional instance configuration:

defrestore_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)."""fromgoogle.cloud.spanner_admin_database_v1import(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_infoprint("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,))

To restore a CMEK-enabled backup in a multi-region instance configuration:

defrestore_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)."""fromgoogle.cloud.spanner_admin_database_v1import(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_infoprint("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,))

Note: The old client library interface code samples for Python are archived inGitHub.

Ruby

To restore a CMEK-enabled backup in a regional instance configuration:

# 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_admininstance_path=database_admin_client.instance_pathproject:project_id,instance:instance_iddb_path=database_admin_client.database_pathproject:project_id,instance:instance_id,database:database_idbackup_path=database_admin_client.backup_pathproject:project_id,instance:instance_id,backup:backup_idencryption_config={encryption_type::CUSTOMER_MANAGED_ENCRYPTION,kms_key_name:kms_key_name}job=database_admin_client.restore_databaseparent:instance_path,database_id:database_id,backup:backup_path,encryption_config:encryption_configputs"Waiting for restore backup operation to complete"job.wait_until_done!database=database_admin_client.get_databasename:db_pathrestore_info=database.restore_infoputs"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}"

To restore a CMEK-enabled backup in a multi-region instance configuration:

# 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_admininstance_path=database_admin_client.instance_path(project:project_id,instance:instance_id)db_path=database_admin_client.database_pathproject:project_id,instance:instance_id,database:database_idbackup_path=database_admin_client.backup_pathproject:project_id,instance:instance_id,backup:backup_idencryption_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_databasename:db_pathrestore_info=database.restore_infoputs"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}"

View audit logs for the Cloud KMS key

  1. Make sure thatlogging is enabledfor the Cloud KMS API in your project.

  2. In the Google Cloud console, go toLogs Explorer.

    Go to Logs Explorer

  3. Limit the log entries to your Cloud KMS key by adding the followinglines to the Query builder:

    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"

    Under normal operations, encrypt and decrypt actions are logged withINFOseverity. These entries are logged as the zones in yourSpanner instance poll the Cloud KMS key about everyfive minutes.

    If Spanner fails to access the key, the operations are loggedasERROR.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.