This page describes how to use manually-created customer-managed encryption keys (CMEK) for Spanner.
To learn more about CMEK, see the Customer-managed encryption keys (CMEK) overview .
Create a CMEK-enabled database
-
Create a key in Cloud Key Management Service (Cloud KMS). Spanner supports creating to following Cloud KMS types:
The key must be in the same location as your Spanner instance. For example, if your Spanner instance configuration is in
us-west1
, then your Cloud KMS key ring location must also beus-west1
.Not every Spanner multi-region instance configuration has a corresponding Cloud KMS key ring location. For Spanner databases in custom, dual-region, or multi-region instance configurations , you can use multiple regional (single-region) Cloud KMS keys to protect your database. For example:
- If your Spanner database is in the multi-region instance
configuration
nam14
, then you can create Cloud KMS keys inus-east4
,northamerica-northeast1
, andus-east1
. - If your database is in a custom instance configuration that uses
nam3
as 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
.
Optional: To see a list of the replica locations in your Spanner instance configuration, use the
gcloud spanner instances get-locations
command:gcloud spanner instances get - locations < var>INSTANCE_ID < / var >
For more information, see the following resources:
- If your Spanner database is in the multi-region instance
configuration
-
Grant Spanner access to the key.
-
In Cloud Shell, create and display the service agent, or display it if the account already exists:
gcloud beta services identity create --service = spanner.googleapis.com \ --project = PROJECT_ID
If you're prompted to install the gcloud Beta Commandscomponent, type
Y
. After installation, the command is automatically restarted.The
gcloud services identity
command creates or gets the service agent that Spanner can use to access the Cloud KMS key on your behalf.The service account ID is formatted like an email address:
Service identity created: service-xxx@gcp-sa-spanner.iam.gserviceaccount.com
-
Grant the Cloud KMS CryptoKey Encrypter/Decrypter (
cloudkms.cryptoKeyEncrypterDecrypter
) role to the service account for each region (--location
) in your Spanner instance configuration. To do so, run thegcloud kms keys add-iam-policybinding
command:gcloud kms keys add-iam-policy-binding KMS_KEY \ --location KMS_KEY_LOCATION \ --keyring KMS_KEY_RING \ --project = PROJECT_ID \ --member serviceAccount: service-xxx@gcp-sa-spanner.iam.gserviceaccount.com \ --role roles/cloudkms.cryptoKeyEncrypterDecrypter
Here's an example output:
Updated IAM policy for key [KMS_KEY]
If you're using multiple Cloud KMS keys to protect your database, run the
gcloud kms keys add-iam-policybinding
command for all the your keys.This role ensures that the service account has permission to both encrypt and decrypt with the Cloud KMS key. For more information, see Cloud KMS permissions and roles .
-
-
Create the database and specify your Cloud KMS key.
Console
Use the console to create databases in regional instance configurations.
-
In the Google Cloud console, go to the Instancespage.
-
Click the instance where you want to create a database.
-
Click Create databaseand fill out the required fields.
-
Click Show encryption options.
-
Select Cloud KMS key.
-
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.
Once the database is created, you can verify that the database is CMEK-enabled by viewing the Database overviewpage.
gcloud
To create a CMEK-enabled database in a regional, custom, or multi-region
instance configuration, run the gcloud spanner databases create
command:
gcloud
spanner
databases
create
DATABASE
\
--project =
SPANNER_PROJECT_ID
\
--instance =
INSTANCE_ID
\
--ddl =
"CREATE TABLE Users (Id INT64 NOT NULL, FirstName STRING(100) NOT NULL, LastName STRING(100) NOT NULL,) PRIMARY KEY (Id)"
\
--kms-project =
KMS_PROJECT_ID
\
--kms-location =
KMS_KEY_LOCATION
\
--kms-keyring =
KMS_KEYRING
\
--kms-keys =
KMS_KEY_1
[
,
KMS_KEY_2
...
]
To verify that a database is CMEK-enabled, run the gcloud spanner databases describe
command:
gcloud
spanner
databases
describe
DATABASE
\
--project =
SPANNER_PROJECT_ID
\
--instance =
INSTANCE_ID
CMEK-enabled databases include a field for encryptionConfig
, as shown in the
following 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-db
state: READY
Client libraries
C#
To create a CMEK-enabled database in a regional instance configuration:
using
Google.Cloud.Spanner.Admin.Database.V1
;
using
Google.Cloud.Spanner.Common.V1
;
using
System
;
using
System.Threading.Tasks
;
public
class
CreateDatabaseWithEncryptionKeyAsyncSample
{
public
async
Task<Database>
CreateDatabaseWithEncryptionKeyAsync
(
string
projectId
,
string
instanceId
,
string
databaseId
,
CryptoKeyName
kmsKeyName
)
{
// Create a DatabaseAdminClient instance that can be used to execute a
// CreateDatabaseRequest with custom encryption configuration options.
DatabaseAdminClient
databaseAdminClient
=
DatabaseAdminClient
.
Create
();
// Define create table statement for table #1.
var
createSingersTable
=
@"CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
ComposerInfo BYTES(MAX)
) PRIMARY KEY (SingerId)"
;
// Define create table statement for table #2.
var
createAlbumsTable
=
@"CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
;
// Create the CreateDatabase request with encryption configuration and execute it.
var
request
=
new
CreateDatabaseRequest
{
ParentAsInstanceName
=
InstanceName
.
FromProjectInstance
(
projectId
,
instanceId
),
CreateStatement
=
$"CREATE DATABASE `{databaseId}`"
,
ExtraStatements
=
{
createSingersTable
,
createAlbumsTable
},
EncryptionConfig
=
new
EncryptionConfig
{
KmsKeyNameAsCryptoKeyName
=
kmsKeyName
,
},
};
var
operation
=
await
databaseAdminClient
.
CreateDatabaseAsync
(
request
);
// Wait until the operation has finished.
Console
.
WriteLine
(
"Waiting for the operation to finish."
);
var
completedResponse
=
await
operation
.
PollUntilCompletedAsync
();
if
(
completedResponse
.
IsFaulted
)
{
Console
.
WriteLine
(
$"Error while creating database: {completedResponse.Exception}"
);
throw
completedResponse
.
Exception
;
}
var
database
=
completedResponse
.
Result
;
Console
.
WriteLine
(
$"Database {database.Name} created with encryption key {database. EncryptionConfig
.KmsKeyName}"
);
return
database
;
}
}
To create a CMEK-enabled database in a multi-region instance configuration:
using
Google.Cloud.Spanner.Admin.Database.V1
;
using
Google.Cloud.Spanner.Common.V1
;
using
System
;
using
System.Collections.Generic
;
using
System.Threading.Tasks
;
public
class
CreateDatabaseWithMultiRegionEncryptionAsyncSample
{
public
async
Task<Database>
CreateDatabaseWithMultiRegionEncryptionAsync
(
string
projectId
,
string
instanceId
,
string
databaseId
,
IEnumerable<CryptoKeyName>
kmsKeyNames
)
{
// Create a DatabaseAdminClient instance that can be used to execute a
// CreateDatabaseRequest with custom encryption configuration options.
DatabaseAdminClient
databaseAdminClient
=
DatabaseAdminClient
.
Create
();
// Define create table statement for table #1.
var
createSingersTable
=
@"CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
ComposerInfo BYTES(MAX)
) PRIMARY KEY (SingerId)"
;
// Define create table statement for table #2.
var
createAlbumsTable
=
@"CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
;
// Create the CreateDatabase request with encryption configuration and execute it.
var
request
=
new
CreateDatabaseRequest
{
ParentAsInstanceName
=
InstanceName
.
FromProjectInstance
(
projectId
,
instanceId
),
CreateStatement
=
$"CREATE DATABASE `{databaseId}`"
,
ExtraStatements
=
{
createSingersTable
,
createAlbumsTable
},
EncryptionConfig
=
new
EncryptionConfig
{
KmsKeyNamesAsCryptoKeyNames
=
{
kmsKeyNames
},
},
};
var
operation
=
await
databaseAdminClient
.
CreateDatabaseAsync
(
request
);
// Wait until the operation has finished.
Console
.
WriteLine
(
"Waiting for the operation to finish."
);
var
completedResponse
=
await
operation
.
PollUntilCompletedAsync
();
if
(
completedResponse
.
IsFaulted
)
{
Console
.
WriteLine
(
$"Error while creating database: {completedResponse.Exception}"
);
throw
completedResponse
.
Exception
;
}
var
database
=
completedResponse
.
Result
;
Console
.
WriteLine
(
$"Database {database.Name} created with encryption keys {string.Join("
,
", kmsKeyNames)}"
);
return
database
;
}
}
C++
To create a CMEK-enabled database in a regional instance configuration:
void
CreateDatabaseWithEncryptionKey
(
google
::
cloud
::
spanner_admin
::
DatabaseAdminClient
client
,
std
::
string
const
&
project_id
,
std
::
string
const
&
instance_id
,
std
::
string
const
&
database_id
,
google
::
cloud
::
KmsKeyName
const
&
encryption_key
)
{
google
::
cloud
::
spanner
::
Database
database
(
project_id
,
instance_id
,
database_id
);
google
::
spanner
::
admin
::
database
::
v1
::
CreateDatabaseRequest
request
;
request
.
set_parent
(
database
.
instance
().
FullName
());
request
.
set_create_statement
(
"CREATE DATABASE `"
+
database
.
database_id
()
+
"`"
);
request
.
add_extra_statements
(
R
"
""(
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
FullName STRING(2049)
AS (ARRAY_TO_STRING([FirstName, LastName], " ")) STORED
) PRIMARY KEY (SingerId)
)""
"
);
request
.
add_extra_statements
(
R
"
""(
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE
)""
"
);
request
.
mutable_encryption_config
()
-
> set_kms_key_name
(
encryption_key
.
FullName
());
auto
db
=
client
.
CreateDatabase
(
request
).
get
();
if
(
!
db
)
throw
std
::
move
(
db
).
status
();
std
::
cout
<<
"Database "
<<
db
-
> name
()
<<
" created"
;
std
::
cout
<<
" using encryption key "
<<
encryption_key
.
FullName
();
std
::
cout
<<
".
\n
"
;
}
To create a CMEK-enabled database in a multi-region instance configuration:
void
CreateDatabaseWithMRCMEK
(
google
::
cloud
::
spanner_admin
::
DatabaseAdminClient
client
,
std
::
string
const
&
project_id
,
std
::
string
const
&
instance_id
,
std
::
string
const
&
database_id
,
std
::
vector<google
::
cloud
::
KmsKeyName
>
const
&
encryption_keys
)
{
google
::
cloud
::
spanner
::
Database
database
(
project_id
,
instance_id
,
database_id
);
google
::
spanner
::
admin
::
database
::
v1
::
CreateDatabaseRequest
request
;
request
.
set_parent
(
database
.
instance
().
FullName
());
request
.
set_create_statement
(
"CREATE DATABASE `"
+
database
.
database_id
()
+
"`"
);
request
.
add_extra_statements
(
R
"
""(
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
FullName STRING(2049)
AS (ARRAY_TO_STRING([FirstName, LastName], " ")) STORED
) PRIMARY KEY (SingerId)
)""
"
);
request
.
add_extra_statements
(
R
"
""(
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE
)""
"
);
for
(
google
::
cloud
::
KmsKeyName
const
&
encryption_key
:
encryption_keys
)
{
request
.
mutable_encryption_config
()
-
> add_kms_key_names
(
encryption_key
.
FullName
());
}
auto
db
=
client
.
CreateDatabase
(
request
).
get
();
if
(
!
db
)
throw
std
::
move
(
db
).
status
();
std
::
cout
<<
"Database "
<<
db
-
> name
()
<<
" created"
;
PrintKmsKeys
(
encryption_keys
);
}
Go
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"
)
func
createDatabaseWithCustomerManagedEncryptionKey
(
ctx
context
.
Context
,
w
io
.
Writer
,
db
,
kmsKeyName
string
)
error
{
// db = `projects/<project>/instances/<instance-id>/database/<database-id>`
// kmsKeyName = `projects/<project>/locations/<location>/keyRings/<key_ring>/cryptoKeys/<kms_key_name>`
matches
:=
regexp
.
MustCompile
(
"^(.+)/databases/(.+)$"
).
FindStringSubmatch
(
db
)
if
matches
==
nil
||
len
(
matches
)
!=
3
{
return
fmt
.
Errorf
(
"createDatabaseWithCustomerManagedEncryptionKey: invalid database id %q"
,
db
)
}
instanceName
:=
matches
[
1
]
databaseId
:=
matches
[
2
]
adminClient
,
err
:=
database
.
NewDatabaseAdminClient
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createDatabaseWithCustomerManagedEncryptionKey.NewDatabaseAdminClient: %w"
,
err
)
}
defer
adminClient
.
Close
()
// Create a database with tables using a Customer Managed Encryption Key
req
:=
adminpb
.
CreateDatabaseRequest
{
Parent
:
instanceName
,
CreateStatement
:
"CREATE DATABASE `"
+
databaseId
+
"`"
,
ExtraStatements
:
[]
string
{
`CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX)
) PRIMARY KEY (SingerId)`
,
`CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE`
,
},
EncryptionConfig
:
& adminpb
.
EncryptionConfig
{
KmsKeyName
:
kmsKeyName
},
}
op
,
err
:=
adminClient
.
CreateDatabase
(
ctx
,
& req
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createDatabaseWithCustomerManagedEncryptionKey.CreateDatabase: %w"
,
err
)
}
dbObj
,
err
:=
op
.
Wait
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createDatabaseWithCustomerManagedEncryptionKey.Wait: %w"
,
err
)
}
fmt
.
Fprintf
(
w
,
"Created database [%s] using encryption key %q\n"
,
dbObj
.
Name
,
dbObj
.
EncryptionConfig
.
KmsKeyName
)
return
nil
}
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.
func
createDatabaseWithCustomerManagedMultiRegionEncryptionKey
(
ctx
context
.
Context
,
w
io
.
Writer
,
projectID
,
instanceID
,
databaseID
string
,
kmsKeyNames
[]
string
)
error
{
// projectID = `my-project`
// instanceID = `my-instance`
// databaseID = `my-database`
// kmsKeyNames := []string{"projects/my-project/locations/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
// "projects/my-project/locations/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
// "projects/my-project/locations/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>",
// }
adminClient
,
err
:=
database
.
NewDatabaseAdminClient
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createDatabaseWithCustomerManagedMultiRegionEncryptionKey.NewDatabaseAdminClient: %w"
,
err
)
}
defer
adminClient
.
Close
()
// Create a database with tables using a Customer Managed Multi-Region Encryption Key
req
:=
adminpb
.
CreateDatabaseRequest
{
Parent
:
fmt
.
Sprintf
(
"projects/%s/instances/%s"
,
projectID
,
instanceID
),
CreateStatement
:
"CREATE DATABASE `"
+
databaseID
+
"`"
,
ExtraStatements
:
[]
string
{
`CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX)
) PRIMARY KEY (SingerId)`
,
`CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE`
,
},
EncryptionConfig
:
& adminpb
.
EncryptionConfig
{
KmsKeyNames
:
kmsKeyNames
},
}
op
,
err
:=
adminClient
.
CreateDatabase
(
ctx
,
& req
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createDatabaseWithCustomerManagedMultiRegionEncryptionKey.CreateDatabase: %w"
,
err
)
}
dbObj
,
err
:=
op
.
Wait
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createDatabaseWithCustomerManagedMultiRegionEncryptionKey.Wait: %w"
,
err
)
}
fmt
.
Fprintf
(
w
,
"Created database [%s] using multi-region encryption keys %q\n"
,
dbObj
.
Name
,
dbObj
.
EncryptionConfig
.
GetKmsKeyNames
())
return
nil
}
Java
To create a CMEK-enabled database in a regional instance configuration:
import
com.google.cloud.spanner. Spanner
;
import
com.google.cloud.spanner. SpannerExceptionFactory
;
import
com.google.cloud.spanner. SpannerOptions
;
import
com.google.cloud.spanner.admin.database.v1. DatabaseAdminClient
;
import
com.google.common.collect.ImmutableList
;
import
com.google.spanner.admin.database.v1. CreateDatabaseRequest
;
import
com.google.spanner.admin.database.v1. Database
;
import
com.google.spanner.admin.database.v1. EncryptionConfig
;
import
com.google.spanner.admin.database.v1. InstanceName
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeoutException
;
public
class
CreateDatabaseWithEncryptionKey
{
static
void
createDatabaseWithEncryptionKey
()
{
// TODO(developer): Replace these variables before running the sample.
String
projectId
=
"my-project"
;
String
instanceId
=
"my-instance"
;
String
databaseId
=
"my-database"
;
String
kmsKeyName
=
"projects/"
+
projectId
+
"/locations/<location>/keyRings/<keyRing>/cryptoKeys/<keyId>"
;
try
(
Spanner
spanner
=
SpannerOptions
.
newBuilder
().
setProjectId
(
projectId
).
build
().
getService
();
DatabaseAdminClient
adminClient
=
spanner
.
createDatabaseAdminClient
())
{
createDatabaseWithEncryptionKey
(
adminClient
,
projectId
,
instanceId
,
databaseId
,
kmsKeyName
);
}
}
static
void
createDatabaseWithEncryptionKey
(
DatabaseAdminClient
adminClient
,
String
projectId
,
String
instanceId
,
String
databaseId
,
String
kmsKeyName
)
{
InstanceName
instanceName
=
InstanceName
.
of
(
projectId
,
instanceId
);
CreateDatabaseRequest
request
=
CreateDatabaseRequest
.
newBuilder
()
.
setParent
(
instanceName
.
toString
())
.
setCreateStatement
(
"CREATE DATABASE `"
+
databaseId
+
"`"
)
.
setEncryptionConfig
(
EncryptionConfig
.
newBuilder
().
setKmsKeyName
(
kmsKeyName
).
build
())
.
addAllExtraStatements
(
ImmutableList
.
of
(
"CREATE TABLE Singers ("
+
" SingerId INT64 NOT NULL,"
+
" FirstName STRING(1024),"
+
" LastName STRING(1024),"
+
" SingerInfo BYTES(MAX)"
+
") PRIMARY KEY (SingerId)"
,
"CREATE TABLE Albums ("
+
" SingerId INT64 NOT NULL,"
+
" AlbumId INT64 NOT NULL,"
+
" AlbumTitle STRING(MAX)"
+
") PRIMARY KEY (SingerId, AlbumId),"
+
" INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
))
.
build
();
try
{
System
.
out
.
println
(
"Waiting for operation to complete..."
);
Database
createdDatabase
=
adminClient
.
createDatabaseAsync
(
request
).
get
(
120
,
TimeUnit
.
SECONDS
);
System
.
out
.
printf
(
"Database %s created with encryption key %s%n"
,
createdDatabase
.
getName
(),
createdDatabase
.
getEncryptionConfig
().
getKmsKeyName
()
);
}
catch
(
ExecutionException
e
)
{
// If the operation failed during execution, expose the cause.
throw
SpannerExceptionFactory
.
asSpannerException
(
e
.
getCause
());
}
catch
(
InterruptedException
e
)
{
// Throw when a thread is waiting, sleeping, or otherwise occupied,
// and the thread is interrupted, either before or during the activity.
throw
SpannerExceptionFactory
.
propagateInterrupt
(
e
);
}
catch
(
TimeoutException
e
)
{
// If the operation timed out propagates the timeout
throw
SpannerExceptionFactory
.
propagateTimeout
(
e
);
}
}
}
To create a CMEK-enabled database in a multi-region instance configuration:
import
com.google.cloud.spanner. Spanner
;
import
com.google.cloud.spanner. SpannerExceptionFactory
;
import
com.google.cloud.spanner. SpannerOptions
;
import
com.google.cloud.spanner.admin.database.v1. DatabaseAdminClient
;
import
com.google.common.collect.ImmutableList
;
import
com.google.spanner.admin.database.v1. CreateDatabaseRequest
;
import
com.google.spanner.admin.database.v1. Database
;
import
com.google.spanner.admin.database.v1. EncryptionConfig
;
import
com.google.spanner.admin.database.v1. InstanceName
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeoutException
;
public
class
CreateDatabaseWithMultiRegionEncryptionKey
{
static
void
createDatabaseWithEncryptionKey
()
{
// TODO(developer): Replace these variables before running the sample.
String
projectId
=
"my-project"
;
String
instanceId
=
"my-instance"
;
String
databaseId
=
"my-database"
;
String
[]
kmsKeyNames
=
new
String
[]
{
"projects/"
+
projectId
+
"/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>"
,
"projects/"
+
projectId
+
"/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>"
,
"projects/"
+
projectId
+
"/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>"
};
try
(
Spanner
spanner
=
SpannerOptions
.
newBuilder
().
setProjectId
(
projectId
).
build
().
getService
();
DatabaseAdminClient
adminClient
=
spanner
.
createDatabaseAdminClient
())
{
createDatabaseWithMultiRegionEncryptionKey
(
adminClient
,
projectId
,
instanceId
,
databaseId
,
kmsKeyNames
);
}
}
static
void
createDatabaseWithMultiRegionEncryptionKey
(
DatabaseAdminClient
adminClient
,
String
projectId
,
String
instanceId
,
String
databaseId
,
String
[]
kmsKeyNames
)
{
InstanceName
instanceName
=
InstanceName
.
of
(
projectId
,
instanceId
);
CreateDatabaseRequest
request
=
CreateDatabaseRequest
.
newBuilder
()
.
setParent
(
instanceName
.
toString
())
.
setCreateStatement
(
"CREATE DATABASE `"
+
databaseId
+
"`"
)
.
setEncryptionConfig
(
EncryptionConfig
.
newBuilder
()
.
addAllKmsKeyNames
(
ImmutableList
.
copyOf
(
kmsKeyNames
))
.
build
())
.
addAllExtraStatements
(
ImmutableList
.
of
(
"CREATE TABLE Singers ("
+
" SingerId INT64 NOT NULL,"
+
" FirstName STRING(1024),"
+
" LastName STRING(1024),"
+
" SingerInfo BYTES(MAX)"
+
") PRIMARY KEY (SingerId)"
,
"CREATE TABLE Albums ("
+
" SingerId INT64 NOT NULL,"
+
" AlbumId INT64 NOT NULL,"
+
" AlbumTitle STRING(MAX)"
+
") PRIMARY KEY (SingerId, AlbumId),"
+
" INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
))
.
build
();
try
{
System
.
out
.
println
(
"Waiting for operation to complete..."
);
Database
createdDatabase
=
adminClient
.
createDatabaseAsync
(
request
).
get
(
120
,
TimeUnit
.
SECONDS
);
System
.
out
.
printf
(
"Database %s created with encryption keys %s%n"
,
createdDatabase
.
getName
(),
createdDatabase
.
getEncryptionConfig
().
getKmsKeyNamesList
());
}
catch
(
ExecutionException
e
)
{
// If the operation failed during execution, expose the cause.
throw
SpannerExceptionFactory
.
asSpannerException
(
e
.
getCause
());
}
catch
(
InterruptedException
e
)
{
// Throw when a thread is waiting, sleeping, or otherwise occupied,
// and the thread is interrupted, either before or during the activity.
throw
SpannerExceptionFactory
.
propagateInterrupt
(
e
);
}
catch
(
TimeoutException
e
)
{
// If the operation timed out propagates the timeout
throw
SpannerExceptionFactory
.
propagateTimeout
(
e
);
}
}
}
Node.js
To create a CMEK-enabled database in a regional instance configuration:
// Imports the Google Cloud client library
const
{
Spanner
,
protos
}
=
require
(
' @google-cloud/spanner
'
);
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const keyName =
// 'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key';
// creates a client
const
spanner
=
new
Spanner
({
projectId
:
projectId
,
});
// Gets a reference to a Cloud Spanner Database Admin Client object
const
databaseAdminClient
=
spanner
.
getDatabaseAdminClient
();
// Creates a database
const
[
operation
]
=
await
databaseAdminClient
.
createDatabase
({
createStatement
:
'CREATE DATABASE `'
+
databaseId
+
'`'
,
parent
:
databaseAdminClient
.
instancePath
(
projectId
,
instanceId
),
encryptionConfig
:
(
protos
.
google
.
spanner
.
admin
.
database
.
v1
.
EncryptionConfig
=
{
kmsKeyName
:
keyName
,
}),
});
console
.
log
(
`Waiting for operation on
${
databaseId
}
to complete...`
);
await
operation
.
promise
();
console
.
log
(
`Created database
${
databaseId
}
on instance
${
instanceId
}
.`
);
// Get encryption key
const
[
metadata
]
=
await
databaseAdminClient
.
getDatabase
({
name
:
databaseAdminClient
.
databasePath
(
projectId
,
instanceId
,
databaseId
),
});
console
.
log
(
`Database encrypted with key
${
metadata
.
encryptionConfig
.
kmsKeyName
}
.`
,
);
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 library
const
{
Spanner
,
protos
}
=
require
(
' @google-cloud/spanner
'
);
// creates a client
const
spanner
=
new
Spanner
({
projectId
:
projectId
,
});
// Gets a reference to a Cloud Spanner Database Admin Client object
const
databaseAdminClient
=
spanner
.
getDatabaseAdminClient
();
async
function
createDatabaseWithMultipleKmsKeys
()
{
// Creates a database
const
[
operation
]
=
await
databaseAdminClient
.
createDatabase
({
createStatement
:
'CREATE DATABASE `'
+
databaseId
+
'`'
,
parent
:
databaseAdminClient
.
instancePath
(
projectId
,
instanceId
),
encryptionConfig
:
(
protos
.
google
.
spanner
.
admin
.
database
.
v1
.
EncryptionConfig
=
{
kmsKeyNames
:
kmsKeyNames
.
split
(
','
),
}),
});
console
.
log
(
`Waiting for operation on
${
databaseId
}
to complete...`
);
await
operation
.
promise
();
console
.
log
(
`Created database
${
databaseId
}
on instance
${
instanceId
}
.`
);
// Get encryption key
const
[
metadata
]
=
await
databaseAdminClient
.
getDatabase
({
name
:
databaseAdminClient
.
databasePath
(
projectId
,
instanceId
,
databaseId
),
});
console
.
log
(
`Database encrypted with keys
${
metadata
.
encryptionConfig
.
kmsKeyNames
}
.`
,
);
}
createDatabaseWithMultipleKmsKeys
();
PHP
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());
}
}
Python
To create a CMEK-enabled database in a regional instance configuration:
def
create_database_with_encryption_key
(
instance_id
,
database_id
,
kms_key_name
):
"""Creates a database with tables using a Customer Managed Encryption Key (CMEK)."""
from
google.cloud.spanner_admin_database_v1
import
EncryptionConfig
from
google.cloud.spanner_admin_database_v1.types
import
spanner_database_admin
spanner_client
=
spanner
.
Client
()
database_admin_api
=
spanner_client
.
database_admin_api
request
=
spanner_database_admin
.
CreateDatabaseRequest
(
parent
=
database_admin_api
.
instance_path
(
spanner_client
.
project
,
instance_id
),
create_statement
=
f
"CREATE DATABASE `
{
database_id
}
`"
,
extra_statements
=
[
"""CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX)
) PRIMARY KEY (SingerId)"""
,
"""CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE"""
,
],
encryption_config
=
EncryptionConfig
(
kms_key_name
=
kms_key_name
),
)
operation
=
database_admin_api
.
create_database
(
request
=
request
)
print
(
"Waiting for operation to complete..."
)
database
=
operation
.
result
(
OPERATION_TIMEOUT_SECONDS
)
print
(
"Database
{}
created with encryption key
{}
"
.
format
(
database
.
name
,
database
.
encryption_config
.
kms_key_name
)
)
To create a CMEK-enabled database in a multi-region instance configuration:
def
create_database_with_multiple_kms_keys
(
instance_id
,
database_id
,
kms_key_names
):
"""Creates a database with tables using multiple KMS keys(CMEK)."""
from
google.cloud.spanner_admin_database_v1
import
EncryptionConfig
from
google.cloud.spanner_admin_database_v1.types
import
spanner_database_admin
spanner_client
=
spanner
.
Client
()
database_admin_api
=
spanner_client
.
database_admin_api
request
=
spanner_database_admin
.
CreateDatabaseRequest
(
parent
=
database_admin_api
.
instance_path
(
spanner_client
.
project
,
instance_id
),
create_statement
=
f
"CREATE DATABASE `
{
database_id
}
`"
,
extra_statements
=
[
"""CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX)
) PRIMARY KEY (SingerId)"""
,
"""CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE"""
,
],
encryption_config
=
EncryptionConfig
(
kms_key_names
=
kms_key_names
),
)
operation
=
database_admin_api
.
create_database
(
request
=
request
)
print
(
"Waiting for operation to complete..."
)
database
=
operation
.
result
(
OPERATION_TIMEOUT_SECONDS
)
print
(
"Database
{}
created with multiple KMS keys
{}
"
.
format
(
database
.
name
,
database
.
encryption_config
.
kms_key_names
)
)
Ruby
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_admin
instance_path
=
database_admin_client
.
instance_path
project
:
project_id
,
instance
:
instance_id
db_path
=
database_admin_client
.
database_path
project
:
project_id
,
instance
:
instance_id
,
database
:
database_id
job
=
database_admin_client
.
create_database
parent
:
instance_path
,
create_statement
:
"CREATE DATABASE `
#{
database_id
}
`"
,
extra_statements
:
[
"CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX)
) PRIMARY KEY (SingerId)"
,
"CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
]
,
encryption_config
:
{
kms_key_name
:
kms_key_name
}
puts
"Waiting for create database operation to complete"
job
.
wait_until_done!
database
=
database_admin_client
.
get_database
name
:
db_path
puts
"Database
#{
database_id
}
created with encryption key
#{
database
.
encryption_config
.
kms_key_name
}
"
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_admin
instance_path
=
database_admin_client
.
instance_path
(
project
:
project_id
,
instance
:
instance_id
)
encryption_config
=
{
kms_key_names
:
kms_key_names
}
db_path
=
database_admin_client
.
database_path
(
project
:
project_id
,
instance
:
instance_id
,
database
:
database_id
)
job
=
database_admin_client
.
create_database
(
parent
:
instance_path
,
create_statement
:
"CREATE DATABASE `
#{
database_id
}
`"
,
extra_statements
:
[
<< ~
STATEMENT
,
CREATE
TABLE
Singers
(
SingerId
INT64
NOT
NULL
,
FirstName
STRING
(
1024
),
LastName
STRING
(
1024
),
SingerInfo
BYTES
(
MAX
)
)
PRIMARY
KEY
(
SingerId
)
STATEMENT
<< ~
STATEMENT
CREATE
TABLE
Albums
(
SingerId
INT64
NOT
NULL
,
AlbumId
INT64
NOT
NULL
,
AlbumTitle
STRING
(
MAX
)
)
PRIMARY
KEY
(
SingerId
,
AlbumId
),
INTERLEAVE
IN
PARENT
Singers
ON
DELETE
CASCADE
STATEMENT
]
,
encryption_config
:
encryption_config
)
puts
"Waiting for create database operation to complete"
job
.
wait_until_done!
database
=
database_admin_client
.
get_database
name
:
db_path
puts
"Database
#{
database_id
}
created with encryption key "
\
"
#{
database
.
encryption_config
.
kms_key_names
}
"
View the key versions in use
The database's encryption_info
field shows information about key versions.
When a database's key version changes, the change isn't immediately propagated
to encryption_info
. There might be a delay before the change is reflected in
this field.
Console
-
In the Google Cloud console, go to the Instancespage.
-
Click the instance containing the database you want to view.
-
Click the database.
Encryption information is displayed on the Database detailspage.
gcloud
You can get a database's encryption_info
by running the gcloud spanner databases describe
or gcloud spanner databases list
command. For example:
gcloud
spanner
databases
describe
DATABASE
\
--project =
SPANNER_PROJECT_ID
\
--instance =
INSTANCE_ID
Here's an example output:
name: projects/my-project/instances/test-instance/databases/example-db
encryptionInfo:
- encryptionType: CUSTOMER_MANAGED_ENCRYPTION
kmsKeyVersion: projects/my-kms-project/locations/my-kms-key1-location/keyRings/my-kms-key-ring1/cryptoKeys/my-kms-key1/cryptoKeyVersions/1
- encryptionType: CUSTOMER_MANAGED_ENCRYPTION
kmsKeyVersion: projects/my-kms-project/locations/my-kms-key2-location/keyRings/my-kms-key-ring2/cryptoKeys/my-kms-key2/cryptoKeyVersions/1
Disable the key
-
Disable the key version(s) that are in use by following these instructions for each key version.
-
Wait for the change to take effect. Disabling a key can take up to three hours to propagate .
-
To confirm that the database is no longer accessible, execute a query in the CMEK-disabled database:
gcloud spanner databases execute-sql DATABASE \ --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
-
Enable the key versions that are in use by the database by following these instructions for each key version.
-
Wait for the change to take effect. Enabling a key can take up to three hours to propagate.
-
To confirm that the database is no longer accessible, execute a query in the CMEK-enabled database:
gcloud spanner databases execute-sql DATABASE \ --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
You can use Spanner backups to create backups of your databases. By default, Spanner backups created from a database use the same encryption configuration as the database itself. You can optionally specify a different encryption configuration for a backup.
Console
Use the console to create backups in regional instance configurations.
-
In the Google Cloud console, go to the Instancespage.
-
Click the instance name that contains the database that you want to back up.
-
Click the database.
-
In the navigation pane, click Backup/Restore.
-
In the Backupstab, click Create backup.
-
Enter a backup name and select an expiration date.
-
Optional: Click Show encryption options.
a. If you want to use a different encryption configuration for your backup, click the slider next to Use existing encryption.
a. Select Cloud 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.
-
Click Create.
The Backupstable displays encryption information for each backup.
gcloud
To create a CMEK-enabled backup in a regional, custom, or multi-region
instance configuration, run the gcloud spanner backups create
command:
gcloud
spanner
backups
create
BACKUP
\
--project =
SPANNER_PROJECT_ID
\
--instance =
INSTANCE_ID
\
--database =
DATABASE
\
--retention-period =
RETENTION_PERIOD
\
--encryption-type =
customer_managed_encryption
\
--kms-project =
KMS_PROJECT_ID
\
--kms-location =
KMS_KEY_LOCATION
\
--kms-keyring =
KMS_KEY_RING
\
--kms-keys =
KMS_KEY_1
[
,
KMS_KEY_2
...
]
--async
To verify that the backup created is CMEK encrypted:
gcloud
spanner
backups
describe
BACKUP
\
--project =
SPANNER_PROJECT_ID
\
--instance =
INSTANCE_ID
Client libraries
C#
To create a CMEK-enabled backup in a regional instance configuration:
using
Google.Cloud.Spanner.Admin.Database.V1
;
using
Google.Cloud.Spanner.Common.V1
;
using
Google.Protobuf.WellKnownTypes
;
using
System
;
using
System.Threading.Tasks
;
public
class
CreateBackupWithEncryptionKeyAsyncSample
{
public
async
Task<Backup>
CreateBackupWithEncryptionKeyAsync
(
string
projectId
,
string
instanceId
,
string
databaseId
,
string
backupId
,
CryptoKeyName
kmsKeyName
)
{
// Create a DatabaseAdminClient instance.
DatabaseAdminClient
databaseAdminClient
=
DatabaseAdminClient
.
Create
();
// Create the CreateBackupRequest with encryption configuration.
CreateBackupRequest
request
=
new
CreateBackupRequest
{
ParentAsInstanceName
=
InstanceName
.
FromProjectInstance
(
projectId
,
instanceId
),
BackupId
=
backupId
,
Backup
=
new
Backup
{
DatabaseAsDatabaseName
=
DatabaseName
.
FromProjectInstanceDatabase
(
projectId
,
instanceId
,
databaseId
),
ExpireTime
=
DateTime
.
UtcNow
.
AddDays
(
14
).
ToTimestamp
(),
},
EncryptionConfig
=
new
CreateBackupEncryptionConfig
{
EncryptionType
=
CreateBackupEncryptionConfig
.
Types
.
EncryptionType
.
CustomerManagedEncryption
,
KmsKeyNameAsCryptoKeyName
=
kmsKeyName
,
},
};
// Execute the CreateBackup request.
var
operation
=
await
databaseAdminClient
.
CreateBackupAsync
(
request
);
Console
.
WriteLine
(
"Waiting for the operation to finish."
);
// Poll until the returned long-running operation is complete.
var
completedResponse
=
await
operation
.
PollUntilCompletedAsync
();
if
(
completedResponse
.
IsFaulted
)
{
Console
.
WriteLine
(
$"Error while creating backup: {completedResponse.Exception}"
);
throw
completedResponse
.
Exception
;
}
var
backup
=
completedResponse
.
Result
;
Console
.
WriteLine
(
$"Backup {backup.Name} of size {backup. SizeBytes
} bytes "
+
$"was created at {backup.CreateTime} "
+
$"using encryption key {kmsKeyName}"
);
return
backup
;
}
}
To create a CMEK-enabled backup in a multi-region instance configuration:
using
Google.Cloud.Spanner.Admin.Database.V1
;
using
Google.Cloud.Spanner.Common.V1
;
using
Google.Protobuf.WellKnownTypes
;
using
System
;
using
System.Collections.Generic
;
using
System.Threading.Tasks
;
public
class
CreateBackupWithMultiRegionEncryptionAsyncSample
{
public
async
Task<Backup>
CreateBackupWithMultiRegionEncryptionAsync
(
string
projectId
,
string
instanceId
,
string
databaseId
,
string
backupId
,
IEnumerable<CryptoKeyName>
kmsKeyNames
)
{
// Create a DatabaseAdminClient instance.
DatabaseAdminClient
databaseAdminClient
=
DatabaseAdminClient
.
Create
();
// Create the CreateBackupRequest with encryption configuration.
CreateBackupRequest
request
=
new
CreateBackupRequest
{
ParentAsInstanceName
=
InstanceName
.
FromProjectInstance
(
projectId
,
instanceId
),
BackupId
=
backupId
,
Backup
=
new
Backup
{
DatabaseAsDatabaseName
=
DatabaseName
.
FromProjectInstanceDatabase
(
projectId
,
instanceId
,
databaseId
),
ExpireTime
=
DateTime
.
UtcNow
.
AddDays
(
14
).
ToTimestamp
(),
},
EncryptionConfig
=
new
CreateBackupEncryptionConfig
{
EncryptionType
=
CreateBackupEncryptionConfig
.
Types
.
EncryptionType
.
CustomerManagedEncryption
,
KmsKeyNamesAsCryptoKeyNames
=
{
kmsKeyNames
},
},
};
// Execute the CreateBackup request.
var
operation
=
await
databaseAdminClient
.
CreateBackupAsync
(
request
);
Console
.
WriteLine
(
"Waiting for the operation to finish."
);
// Poll until the returned long-running operation is complete.
var
completedResponse
=
await
operation
.
PollUntilCompletedAsync
();
if
(
completedResponse
.
IsFaulted
)
{
Console
.
WriteLine
(
$"Error while creating backup: {completedResponse.Exception}"
);
throw
completedResponse
.
Exception
;
}
var
backup
=
completedResponse
.
Result
;
Console
.
WriteLine
(
$"Backup {backup.Name} of size {backup. SizeBytes
} bytes was created with encryption keys {string.Join("
,
", kmsKeyNames)} at {backup.CreateTime}"
);
return
backup
;
}
}
C++
To create a CMEK-enabled backup in a regional instance configuration:
void
CreateBackupWithEncryptionKey
(
google
::
cloud
::
spanner_admin
::
DatabaseAdminClient
client
,
std
::
string
const
&
project_id
,
std
::
string
const
&
instance_id
,
std
::
string
const
&
database_id
,
std
::
string
const
&
backup_id
,
google
::
cloud
::
spanner
::
Timestamp
expire_time
,
google
::
cloud
::
spanner
::
Timestamp
version_time
,
google
::
cloud
::
KmsKeyName
const
&
encryption_key
)
{
google
::
cloud
::
spanner
::
Database
database
(
project_id
,
instance_id
,
database_id
);
google
::
spanner
::
admin
::
database
::
v1
::
CreateBackupRequest
request
;
request
.
set_parent
(
database
.
instance
().
FullName
());
request
.
set_backup_id
(
backup_id
);
request
.
mutable_backup
()
-
> set_database
(
database
.
FullName
());
*
request
.
mutable_backup
()
-
> mutable_expire_time
()
=
expire_time
.
get<google
::
protobuf
::
Timestamp
> ().
value
();
*
request
.
mutable_backup
()
-
> mutable_version_time
()
=
version_time
.
get<google
::
protobuf
::
Timestamp
> ().
value
();
request
.
mutable_encryption_config
()
-
> set_encryption_type
(
google
::
spanner
::
admin
::
database
::
v1
::
CreateBackupEncryptionConfig
::
CUSTOMER_MANAGED_ENCRYPTION
);
request
.
mutable_encryption_config
()
-
> set_kms_key_name
(
encryption_key
.
FullName
());
auto
backup
=
client
.
CreateBackup
(
request
).
get
();
if
(
!
backup
)
throw
std
::
move
(
backup
).
status
();
std
::
cout
<<
"Backup "
<<
backup
-
> name
()
<<
" of "
<<
backup
-
> database
()
<<
" of size "
<<
backup
-
> size_bytes
()
<<
" bytes as of "
<<
google
::
cloud
::
spanner
::
MakeTimestamp
(
backup
-
> version_time
()).
value
()
<<
" was created at "
<<
google
::
cloud
::
spanner
::
MakeTimestamp
(
backup
-
> create_time
()).
value
()
<<
" using encryption key "
<<
encryption_key
.
FullName
()
<<
".
\n
"
;
}
To create a CMEK-enabled backup in a multi-region instance configuration:
void
CreateBackupWithMRCMEK
(
google
::
cloud
::
spanner_admin
::
DatabaseAdminClient
client
,
BackupIdentifier
dst
,
std
::
string
const
&
database_id
,
google
::
cloud
::
spanner
::
Timestamp
expire_time
,
google
::
cloud
::
spanner
::
Timestamp
version_time
,
std
::
vector<google
::
cloud
::
KmsKeyName
>
const
&
encryption_keys
)
{
google
::
cloud
::
spanner
::
Database
database
(
dst
.
project_id
,
dst
.
instance_id
,
database_id
);
google
::
spanner
::
admin
::
database
::
v1
::
CreateBackupRequest
request
;
request
.
set_parent
(
database
.
instance
().
FullName
());
request
.
set_backup_id
(
dst
.
backup_id
);
request
.
mutable_backup
()
-
> set_database
(
database
.
FullName
());
*
request
.
mutable_backup
()
-
> mutable_expire_time
()
=
expire_time
.
get<google
::
protobuf
::
Timestamp
> ().
value
();
*
request
.
mutable_backup
()
-
> mutable_version_time
()
=
version_time
.
get<google
::
protobuf
::
Timestamp
> ().
value
();
request
.
mutable_encryption_config
()
-
> set_encryption_type
(
google
::
spanner
::
admin
::
database
::
v1
::
CreateBackupEncryptionConfig
::
CUSTOMER_MANAGED_ENCRYPTION
);
for
(
google
::
cloud
::
KmsKeyName
const
&
encryption_key
:
encryption_keys
)
{
request
.
mutable_encryption_config
()
-
> add_kms_key_names
(
encryption_key
.
FullName
());
}
auto
backup
=
client
.
CreateBackup
(
request
).
get
();
if
(
!
backup
)
throw
std
::
move
(
backup
).
status
();
std
::
cout
<<
"Backup "
<<
backup
-
> name
()
<<
" of "
<<
backup
-
> database
()
<<
" of size "
<<
backup
-
> size_bytes
()
<<
" bytes as of "
<<
google
::
cloud
::
spanner
::
MakeTimestamp
(
backup
-
> version_time
()).
value
()
<<
" was created at "
<<
google
::
cloud
::
spanner
::
MakeTimestamp
(
backup
-
> create_time
()).
value
();
PrintKmsKeys
(
encryption_keys
);
}
Go
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"
)
func
createBackupWithCustomerManagedEncryptionKey
(
ctx
context
.
Context
,
w
io
.
Writer
,
db
,
backupID
,
kmsKeyName
string
)
error
{
// db = `projects/<project>/instances/<instance-id>/database/<database-id>`
// backupID = `my-backup-id`
// kmsKeyName = `projects/<project>/locations/<location>/keyRings/<key_ring>/cryptoKeys/<kms_key_name>`
matches
:=
regexp
.
MustCompile
(
"^(.+)/databases/(.+)$"
).
FindStringSubmatch
(
db
)
if
matches
==
nil
||
len
(
matches
)
!=
3
{
return
fmt
.
Errorf
(
"createBackupWithCustomerManagedEncryptionKey: invalid database id %q"
,
db
)
}
instanceName
:=
matches
[
1
]
adminClient
,
err
:=
database
.
NewDatabaseAdminClient
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createBackupWithCustomerManagedEncryptionKey.NewDatabaseAdminClient: %w"
,
err
)
}
defer
adminClient
.
Close
()
expireTime
:=
time
.
Now
().
AddDate
(
0
,
0
,
14
)
// Create a backup for a database using a Customer Managed Encryption Key
req
:=
adminpb
.
CreateBackupRequest
{
Parent
:
instanceName
,
BackupId
:
backupID
,
Backup
:
& adminpb
.
Backup
{
Database
:
db
,
ExpireTime
:
& pbt
.
Timestamp
{
Seconds
:
expireTime
.
Unix
(),
Nanos
:
int32
(
expireTime
.
Nanosecond
())},
},
EncryptionConfig
:
& adminpb
.
CreateBackupEncryptionConfig
{
KmsKeyName
:
kmsKeyName
,
EncryptionType
:
adminpb
.
CreateBackupEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION
,
},
}
op
,
err
:=
adminClient
.
CreateBackup
(
ctx
,
& req
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createBackupWithCustomerManagedEncryptionKey.CreateBackup: %w"
,
err
)
}
// Wait for backup operation to complete.
backup
,
err
:=
op
.
Wait
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createBackupWithCustomerManagedEncryptionKey.Wait: %w"
,
err
)
}
// Get the name, create time, backup size and encryption key from the backup.
backupCreateTime
:=
time
.
Unix
(
backup
.
CreateTime
.
Seconds
,
int64
(
backup
.
CreateTime
.
Nanos
))
fmt
.
Fprintf
(
w
,
"Backup %s of size %d bytes was created at %s using encryption key %s\n"
,
backup
.
Name
,
backup
.
SizeBytes
,
backupCreateTime
.
Format
(
time
.
RFC3339
),
kmsKeyName
)
return
nil
}
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.
func
createBackupWithCustomerManagedMultiRegionEncryptionKey
(
ctx
context
.
Context
,
w
io
.
Writer
,
projectID
,
instanceID
,
databaseID
,
backupID
string
,
kmsKeyNames
[]
string
)
error
{
// projectID = `my-project`
// instanceID = `my-instance`
// databaseID = `my-database`
// backupID = `my-backup-id`
// kmsKeyNames := []string{"projects/my-project/locations/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>",
// "projects/my-project/locations/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>",
// "projects/my-project/locations/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>",
// }
adminClient
,
err
:=
database
.
NewDatabaseAdminClient
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createBackupWithCustomerManagedMultiRegionEncryptionKey.NewDatabaseAdminClient: %w"
,
err
)
}
defer
adminClient
.
Close
()
expireTime
:=
time
.
Now
().
AddDate
(
0
,
0
,
14
)
// Create a backup for a database using a Customer Managed Encryption Key
req
:=
adminpb
.
CreateBackupRequest
{
Parent
:
fmt
.
Sprintf
(
"projects/%s/instances/%s"
,
projectID
,
instanceID
),
BackupId
:
backupID
,
Backup
:
& adminpb
.
Backup
{
Database
:
fmt
.
Sprintf
(
"projects/%s/instances/%s/databases/%s"
,
projectID
,
instanceID
,
databaseID
),
ExpireTime
:
& pbt
.
Timestamp
{
Seconds
:
expireTime
.
Unix
(),
Nanos
:
int32
(
expireTime
.
Nanosecond
())},
},
EncryptionConfig
:
& adminpb
.
CreateBackupEncryptionConfig
{
KmsKeyNames
:
kmsKeyNames
,
EncryptionType
:
adminpb
.
CreateBackupEncryptionConfig_CUSTOMER_MANAGED_ENCRYPTION
,
},
}
op
,
err
:=
adminClient
.
CreateBackup
(
ctx
,
& req
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createBackupWithCustomerManagedMultiRegionEncryptionKey.CreateBackup: %w"
,
err
)
}
// Wait for backup operation to complete.
backup
,
err
:=
op
.
Wait
(
ctx
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"createBackupWithCustomerManagedMultiRegionEncryptionKey.Wait: %w"
,
err
)
}
// Get the name, create time, backup size and encryption key from the backup.
backupCreateTime
:=
time
.
Unix
(
backup
.
CreateTime
.
Seconds
,
int64
(
backup
.
CreateTime
.
Nanos
))
fmt
.
Fprintf
(
w
,
"Backup %s of size %d bytes was created at %s using multi-region encryption keys %q\n"
,
backup
.
Name
,
backup
.
SizeBytes
,
backupCreateTime
.
Format
(
time
.
RFC3339
),
kmsKeyNames
)
return
nil
}
Java
To create a CMEK-enabled backup in a regional instance configuration:
import
com.google.cloud.spanner. Spanner
;
import
com.google.cloud.spanner. SpannerExceptionFactory
;
import
com.google.cloud.spanner. SpannerOptions
;
import
com.google.cloud.spanner.admin.database.v1. DatabaseAdminClient
;
import
com.google.protobuf. Timestamp
;
import
com.google.spanner.admin.database.v1. Backup
;
import
com.google.spanner.admin.database.v1. BackupName
;
import
com.google.spanner.admin.database.v1. CreateBackupEncryptionConfig
;
import
com.google.spanner.admin.database.v1. CreateBackupEncryptionConfig
.EncryptionType
;
import
com.google.spanner.admin.database.v1. CreateBackupRequest
;
import
com.google.spanner.admin.database.v1. DatabaseName
;
import
com.google.spanner.admin.database.v1. InstanceName
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeoutException
;
import
org.threeten.bp.LocalDateTime
;
import
org.threeten.bp.OffsetDateTime
;
public
class
CreateBackupWithEncryptionKey
{
static
void
createBackupWithEncryptionKey
()
{
// TODO(developer): Replace these variables before running the sample.
String
projectId
=
"my-project"
;
String
instanceId
=
"my-instance"
;
String
databaseId
=
"my-database"
;
String
backupId
=
"my-backup"
;
String
kmsKeyName
=
"projects/"
+
projectId
+
"/locations/<location>/keyRings/<keyRing>/cryptoKeys/<keyId>"
;
try
(
Spanner
spanner
=
SpannerOptions
.
newBuilder
().
setProjectId
(
projectId
).
build
().
getService
();
DatabaseAdminClient
adminClient
=
spanner
.
createDatabaseAdminClient
())
{
createBackupWithEncryptionKey
(
adminClient
,
projectId
,
instanceId
,
databaseId
,
backupId
,
kmsKeyName
);
}
}
static
Void
createBackupWithEncryptionKey
(
DatabaseAdminClient
adminClient
,
String
projectId
,
String
instanceId
,
String
databaseId
,
String
backupId
,
String
kmsKeyName
)
{
// Set expire time to 14 days from now.
final
Timestamp
expireTime
=
Timestamp
.
newBuilder
().
setSeconds
(
TimeUnit
.
MILLISECONDS
.
toSeconds
((
System
.
currentTimeMillis
()
+
TimeUnit
.
DAYS
.
toMillis
(
14
)))).
build
();
final
BackupName
backupName
=
BackupName
.
of
(
projectId
,
instanceId
,
backupId
);
Backup
backup
=
Backup
.
newBuilder
()
.
setName
(
backupName
.
toString
())
.
setDatabase
(
DatabaseName
.
of
(
projectId
,
instanceId
,
databaseId
).
toString
())
.
setExpireTime
(
expireTime
).
build
();
final
CreateBackupRequest
request
=
CreateBackupRequest
.
newBuilder
()
.
setParent
(
InstanceName
.
of
(
projectId
,
instanceId
).
toString
())
.
setBackupId
(
backupId
)
.
setBackup
(
backup
)
.
setEncryptionConfig
(
CreateBackupEncryptionConfig
.
newBuilder
()
.
setEncryptionType
(
EncryptionType
.
CUSTOMER_MANAGED_ENCRYPTION
)
.
setKmsKeyName
(
kmsKeyName
).
build
()).
build
();
try
{
System
.
out
.
println
(
"Waiting for operation to complete..."
);
backup
=
adminClient
.
createBackupAsync
(
request
).
get
(
1200
,
TimeUnit
.
SECONDS
);
}
catch
(
ExecutionException
e
)
{
// If the operation failed during execution, expose the cause.
throw
SpannerExceptionFactory
.
asSpannerException
(
e
.
getCause
());
}
catch
(
InterruptedException
e
)
{
// Throw when a thread is waiting, sleeping, or otherwise occupied,
// and the thread is interrupted, either before or during the activity.
throw
SpannerExceptionFactory
.
propagateInterrupt
(
e
);
}
catch
(
TimeoutException
e
)
{
// If the operation timed out propagates the timeout
throw
SpannerExceptionFactory
.
propagateTimeout
(
e
);
}
System
.
out
.
printf
(
"Backup %s of size %d bytes was created at %s using encryption key %s%n"
,
backup
.
getName
(),
backup
.
getSizeBytes
(),
LocalDateTime
.
ofEpochSecond
(
backup
.
getCreateTime
().
getSeconds
(),
backup
.
getCreateTime
().
getNanos
(),
OffsetDateTime
.
now
().
getOffset
()),
kmsKeyName
);
return
null
;
}
}
To create a CMEK-enabled backup in a multi-region instance configuration:
import
com.google.cloud.spanner. Spanner
;
import
com.google.cloud.spanner. SpannerExceptionFactory
;
import
com.google.cloud.spanner. SpannerOptions
;
import
com.google.cloud.spanner.admin.database.v1. DatabaseAdminClient
;
import
com.google.common.collect.ImmutableList
;
import
com.google.protobuf. Timestamp
;
import
com.google.spanner.admin.database.v1. Backup
;
import
com.google.spanner.admin.database.v1. BackupName
;
import
com.google.spanner.admin.database.v1. CreateBackupEncryptionConfig
;
import
com.google.spanner.admin.database.v1. CreateBackupEncryptionConfig
.EncryptionType
;
import
com.google.spanner.admin.database.v1. CreateBackupRequest
;
import
com.google.spanner.admin.database.v1. DatabaseName
;
import
com.google.spanner.admin.database.v1. InstanceName
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeoutException
;
import
org.threeten.bp.LocalDateTime
;
import
org.threeten.bp.OffsetDateTime
;
public
class
CreateBackupWithMultiRegionEncryptionKey
{
static
void
createBackupWithMultiRegionEncryptionKey
()
{
// TODO(developer): Replace these variables before running the sample.
String
projectId
=
"my-project"
;
String
instanceId
=
"my-instance"
;
String
databaseId
=
"my-database"
;
String
backupId
=
"my-backup"
;
String
[]
kmsKeyNames
=
new
String
[]
{
"projects/"
+
projectId
+
"/locations/<location1>/keyRings/<keyRing>/cryptoKeys/<keyId>"
,
"projects/"
+
projectId
+
"/locations/<location2>/keyRings/<keyRing>/cryptoKeys/<keyId>"
,
"projects/"
+
projectId
+
"/locations/<location3>/keyRings/<keyRing>/cryptoKeys/<keyId>"
};
try
(
Spanner
spanner
=
SpannerOptions
.
newBuilder
().
setProjectId
(
projectId
).
build
().
getService
();
DatabaseAdminClient
adminClient
=
spanner
.
createDatabaseAdminClient
())
{
createBackupWithMultiRegionEncryptionKey
(
adminClient
,
projectId
,
instanceId
,
databaseId
,
backupId
,
kmsKeyNames
);
}
}
static
Void
createBackupWithMultiRegionEncryptionKey
(
DatabaseAdminClient
adminClient
,
String
projectId
,
String
instanceId
,
String
databaseId
,
String
backupId
,
String
[]
kmsKeyNames
)
{
// Set expire time to 14 days from now.
final
Timestamp
expireTime
=
Timestamp
.
newBuilder
()
.
setSeconds
(
TimeUnit
.
MILLISECONDS
.
toSeconds
(
(
System
.
currentTimeMillis
()
+
TimeUnit
.
DAYS
.
toMillis
(
14
))))
.
build
();
final
BackupName
backupName
=
BackupName
.
of
(
projectId
,
instanceId
,
backupId
);
Backup
backup
=
Backup
.
newBuilder
()
.
setName
(
backupName
.
toString
())
.
setDatabase
(
DatabaseName
.
of
(
projectId
,
instanceId
,
databaseId
).
toString
())
.
setExpireTime
(
expireTime
)
.
build
();
final
CreateBackupRequest
request
=
CreateBackupRequest
.
newBuilder
()
.
setParent
(
InstanceName
.
of
(
projectId
,
instanceId
).
toString
())
.
setBackupId
(
backupId
)
.
setBackup
(
backup
)
.
setEncryptionConfig
(
CreateBackupEncryptionConfig
.
newBuilder
()
.
setEncryptionType
(
EncryptionType
.
CUSTOMER_MANAGED_ENCRYPTION
)
.
addAllKmsKeyNames
(
ImmutableList
.
copyOf
(
kmsKeyNames
))
.
build
())
.
build
();
try
{
System
.
out
.
println
(
"Waiting for operation to complete..."
);
backup
=
adminClient
.
createBackupAsync
(
request
).
get
(
1200
,
TimeUnit
.
SECONDS
);
}
catch
(
ExecutionException
e
)
{
// If the operation failed during execution, expose the cause.
throw
SpannerExceptionFactory
.
asSpannerException
(
e
.
getCause
());
}
catch
(
InterruptedException
e
)
{
// Throw when a thread is waiting, sleeping, or otherwise occupied,
// and the thread is interrupted, either before or during the activity.
throw
SpannerExceptionFactory
.
propagateInterrupt
(
e
);
}
catch
(
TimeoutException
e
)
{
// If the operation timed out propagates the timeout
throw
SpannerExceptionFactory
.
propagateTimeout
(
e
);
}
System
.
out
.
printf
(
"Backup %s of size %d bytes was created at %s using encryption keys %s%n"
,
backup
.
getName
(),
backup
.
getSizeBytes
(),
LocalDateTime
.
ofEpochSecond
(
backup
.
getCreateTime
().
getSeconds
(),
backup
.
getCreateTime
().
getNanos
(),
OffsetDateTime
.
now
().
getOffset
()),
ImmutableList
.
copyOf
(
kmsKeyNames
));
return
null
;
}
}
Node.js
To create a CMEK-enabled backup in a regional instance configuration:
// Imports the Google Cloud client library
const
{
Spanner
,
protos
}
=
require
(
' @google-cloud/spanner
'
);
const
{
PreciseDate
}
=
require
(
' @google-cloud/precise-date
'
);
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// const projectId = 'my-project-id';
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const backupId = 'my-backup';
// const keyName =
// 'projects/my-project-id/my-region/keyRings/my-key-ring/cryptoKeys/my-key';
// Creates a client
const
spanner
=
new
Spanner
({
projectId
:
projectId
,
});
// Gets a reference to a Cloud Spanner Database Admin Client object
const
databaseAdminClient
=
spanner
.
getDatabaseAdminClient
();
// Creates a new backup of the database
try
{
console
.
log
(
`Creating backup of database
${
databaseAdminClient
.
databasePath
(
projectId
,
instanceId
,
databaseId
,
)
}
.`
,
);
// Expire backup 14 days in the future
const
expireTime
=
Date
.
now
()
+
1000
*
60
*
60
*
24
*
14
;
// Create a backup of the state of the database at the current time.
const
[
operation
]
=
await
databaseAdminClient
.
createBackup
({
parent
:
databaseAdminClient
.
instancePath
(
projectId
,
instanceId
),
backupId
:
backupId
,
backup
:
(
protos
.
google
.
spanner
.
admin
.
database
.
v1
.
Backup
=
{
database
:
databaseAdminClient
.
databasePath
(
projectId
,
instanceId
,
databaseId
,
),
expireTime
:
Spanner
.
timestamp
(
expireTime
).
toStruct
(),
name
:
databaseAdminClient
.
backupPath
(
projectId
,
instanceId
,
backupId
),
}),
encryptionConfig
:
{
encryptionType
:
'CUSTOMER_MANAGED_ENCRYPTION'
,
kmsKeyName
:
keyName
,
},
});
console
.
log
(
`Waiting for backup
${
databaseAdminClient
.
backupPath
(
projectId
,
instanceId
,
backupId
,
)
}
to complete...`
,
);
await
operation
.
promise
();
// Verify backup is ready
const
[
backupInfo
]
=
await
databaseAdminClient
.
getBackup
({
name
:
databaseAdminClient
.
backupPath
(
projectId
,
instanceId
,
backupId
),
});
if
(
backupInfo
.
state
===
'READY'
)
{
console
.
log
(
`Backup
${
backupInfo
.
name
}
of size `
+
`
${
backupInfo
.
sizeBytes
}
bytes was created at `
+
`
${
new
PreciseDate
(
backupInfo
.
createTime
).
toISOString
()
}
`
+
`using encryption key
${
backupInfo
.
encryptionInfo
.
kmsKeyVersion
}
`
,
);
}
else
{
console
.
error
(
'ERROR: Backup is not ready.'
);
}
}
catch
(
err
)
{
console
.
error
(
'ERROR:'
,
err
);
}
finally
{
// Close the spanner client when finished.
// The databaseAdminClient does not require explicit closure. The closure of the Spanner client will automatically close the databaseAdminClient.
spanner
.
close
();
}
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 library
const
{
Spanner
,
protos
}
=
require
(
' @google-cloud/spanner
'
);
const
{
PreciseDate
}
=
require
(
' @google-cloud/precise-date
'
);
// Creates a client
const
spanner
=
new
Spanner
({
projectId
:
projectId
,
});
// Gets a reference to a Cloud Spanner Database Admin Client object
const
databaseAdminClient
=
spanner
.
getDatabaseAdminClient
();
async
function
createBackupWithMultipleKmsKeys
()
{
// Creates a new backup of the database
try
{
console
.
log
(
`Creating backup of database
${
databaseAdminClient
.
databasePath
(
projectId
,
instanceId
,
databaseId
,
)
}
.`
,
);
// Expire backup 14 days in the future
const
expireTime
=
Date
.
now
()
+
1000
*
60
*
60
*
24
*
14
;
// Create a backup of the state of the database at the current time.
const
[
operation
]
=
await
databaseAdminClient
.
createBackup
({
parent
:
databaseAdminClient
.
instancePath
(
projectId
,
instanceId
),
backupId
:
backupId
,
backup
:
(
protos
.
google
.
spanner
.
admin
.
database
.
v1
.
Backup
=
{
database
:
databaseAdminClient
.
databasePath
(
projectId
,
instanceId
,
databaseId
,
),
expireTime
:
Spanner
.
timestamp
(
expireTime
).
toStruct
(),
name
:
databaseAdminClient
.
backupPath
(
projectId
,
instanceId
,
backupId
),
}),
encryptionConfig
:
{
encryptionType
:
'CUSTOMER_MANAGED_ENCRYPTION'
,
kmsKeyNames
:
kmsKeyNames
.
split
(
','
),
},
});
console
.
log
(
`Waiting for backup
${
databaseAdminClient
.
backupPath
(
projectId
,
instanceId
,
backupId
,
)
}
to complete...`
,
);
await
operation
.
promise
();
// Verify backup is ready
const
[
backupInfo
]
=
await
databaseAdminClient
.
getBackup
({
name
:
databaseAdminClient
.
backupPath
(
projectId
,
instanceId
,
backupId
),
});
const
kmsKeyVersions
=
backupInfo
.
encryptionInformation
.
map
(
encryptionInfo
=
>
encryptionInfo
.
kmsKeyVersion
)
.
join
(
', '
);
if
(
backupInfo
.
state
===
'READY'
)
{
console
.
log
(
`Backup
${
backupInfo
.
name
}
of size `
+
`
${
backupInfo
.
sizeBytes
}
bytes was created at `
+
`
${
new
PreciseDate
(
backupInfo
.
createTime
).
toISOString
()
}
`
+
`using encryption key
${
kmsKeyVersions
}
`
,
);
}
else
{
console
.
error
(
'ERROR: Backup is not ready.'
);
}
}
catch
(
err
)
{
console
.
error
(
'ERROR:'
,
err
);
}
finally
{
// Close the spanner client when finished.
// The databaseAdminClient does not require explicit closure. The closure of the Spanner client will automatically close the databaseAdminClient.
spanner
.
close
();
}
}
createBackupWithMultipleKmsKeys
();
PHP
To create a CMEK-enabled backup in a regional instance configuration: