Skip to content

Commit

Permalink
feat: customer-managed encryption keys (#1274)
Browse files Browse the repository at this point in the history
  • Loading branch information
skuruppu authored Mar 20, 2021
1 parent a73f9fc commit 51cabc7
Show file tree
Hide file tree
Showing 11 changed files with 565 additions and 12 deletions.
92 changes: 92 additions & 0 deletions samples/backups-create-with-encryption-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Copyright 2021 Google LLC
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

async function createBackupWithEncryptionKey(
instanceId,
databaseId,
backupId,
projectId,
keyName
) {
// [START spanner_create_backup_with_encryption_key]
// Imports the Google Cloud client library and precise date library
const {Spanner} = require('@google-cloud/spanner');
const {PreciseDate} = require('@google-cloud/precise-date');

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

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

// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);

const backup = instance.backup(backupId);

// Creates a new backup of the database
try {
console.log(`Creating backup of database ${database.formattedName_}.`);
const databasePath = database.formattedName_;
// Expire backup 14 days in the future
const expireTime = Date.now() + 1000 * 60 * 60 * 24 * 14;
// Create a backup of the state of the database at the current time.
const [, operation] = await backup.create({
databasePath: databasePath,
expireTime: expireTime,
encryptionConfig: {
encryptionType: 'CUSTOMER_MANAGED_ENCRYPTION',
kmsKeyName: keyName,
},
});

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

// Verify backup is ready
const [backupInfo] = await backup.getMetadata();
if (backupInfo.state === 'READY') {
console.log(
`Backup ${backupInfo.name} of size ` +
`${backupInfo.sizeBytes} bytes was created at ` +
`${new PreciseDate(backupInfo.createTime).toISOString()} ` +
`using encryption key ${backupInfo.encryptionInfo.kmsKeyVersion}`
);
} else {
console.error('ERROR: Backup is not ready.');
}
} catch (err) {
console.error('ERROR:', err);
} finally {
// Close the database when finished.
await database.close();
}
// [END spanner_create_backup_with_encryption_key]
}

module.exports.createBackupWithEncryptionKey = createBackupWithEncryptionKey;
77 changes: 77 additions & 0 deletions samples/backups-restore-with-encryption-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright 2021 Google LLC
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

async function restoreBackupWithEncryptionKey(
instanceId,
databaseId,
backupId,
projectId,
keyName
) {
// [START spanner_restore_backup_with_encryption_key]
// Imports the Google Cloud client library and precise date library
const {Spanner} = require('@google-cloud/spanner');

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

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

// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);

// Restore the database
console.log(
`Restoring database ${database.formattedName_} from backup ${backupId}.`
);
const [, restoreOperation] = await database.restore(
`projects/${projectId}/instances/${instanceId}/backups/${backupId}`,
{
encryptionConfig: {
encryptionType: 'CUSTOMER_MANAGED_ENCRYPTION',
kmsKeyName: keyName,
},
}
);

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

console.log('Database restored from backup.');
const restoreInfo = await database.getRestoreInfo();
const [data] = await database.get();
console.log(
`Database ${restoreInfo.backupInfo.sourceDatabase} was restored ` +
`to ${databaseId} from backup ${restoreInfo.backupInfo.backup} ` +
`using encryption key ${data.metadata.encryptionConfig.kmsKeyName}.`
);
// [END spanner_restore_backup_with_encryption_key]
}

module.exports.restoreBackupWithEncryptionKey = restoreBackupWithEncryptionKey;
32 changes: 32 additions & 0 deletions samples/backups.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@
'use strict';

const {createBackup} = require('./backups-create');
const {
createBackupWithEncryptionKey,
} = require('./backups-create-with-encryption-key');
const {cancelBackup} = require('./backups-cancel');
const {getBackups} = require('./backups-get');
const {getBackupOperations} = require('./backups-get-operations');
const {getDatabaseOperations} = require('./backups-get-database-operations');
const {updateBackup} = require('./backups-update');
const {restoreBackup} = require('./backups-restore');
const {
restoreBackupWithEncryptionKey,
} = require('./backups-restore-with-encryption-key');
const {deleteBackup} = require('./backups-delete');

require('yargs')
Expand All @@ -39,6 +45,19 @@ require('yargs')
Date.parse(opts.versionTime)
)
)
.command(
'createBackupWithEncryptionKey <instanceName> <databaseName> <backupName> <projectId> <keyName>',
'Creates a backup of a Cloud Spanner database using an encryption key.',
{},
opts =>
createBackupWithEncryptionKey(
opts.instanceName,
opts.databaseName,
opts.backupName,
opts.projectId,
opts.keyName
)
)
.command(
'cancelBackup <instanceName> <databaseName> <backupName> <projectId>',
'Creates and cancels a backup of a Cloud Spanner database.',
Expand Down Expand Up @@ -94,6 +113,19 @@ require('yargs')
opts.projectId
)
)
.command(
'restoreBackupWithEncryptionKey <instanceName> <databaseName> <backupName> <projectId> <keyName>',
'Restores a Cloud Spanner database from a backup with an encryption key.',
{},
opts =>
restoreBackupWithEncryptionKey(
opts.instanceName,
opts.databaseName,
opts.backupName,
opts.projectId,
opts.keyName
)
)
.command(
'deleteBackup <instanceName> <databaseName> <backupName> <projectId>',
'Deletes a backup.',
Expand Down
70 changes: 70 additions & 0 deletions samples/database-create-with-encryption-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

async function createDatabaseWithEncryptionKey(
instanceId,
databaseId,
projectId,
keyName
) {
// [START spanner_create_database_with_encryption_key]
// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

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

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

// Gets a reference to a Cloud Spanner instance
const instance = spanner.instance(instanceId);

const request = {
encryptionConfig: {
kmsKeyName: keyName,
},
};

// Creates a database
const [database, operation] = await instance.createDatabase(
databaseId,
request
);

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

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

// Get encryption key
const [data] = await database.get();

console.log(
`Database encrypted with key ${data.metadata.encryptionConfig.kmsKeyName}.`
);
// [END spanner_create_database_with_encryption_key]
}

module.exports.createDatabaseWithEncryptionKey = createDatabaseWithEncryptionKey;
1 change: 1 addition & 0 deletions samples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"test": "mocha system-test --timeout 1600000"
},
"dependencies": {
"@google-cloud/kms": "^2.1.3",
"@google-cloud/precise-date": "^2.0.0",
"@google-cloud/spanner": "^5.5.0",
"yargs": "^16.0.0"
Expand Down
18 changes: 18 additions & 0 deletions samples/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ async function queryDataWithNewColumn(instanceId, databaseId, projectId) {
const {
createDatabaseWithVersionRetentionPeriod,
} = require('./database-create-with-version-retention-period');
const {
createDatabaseWithEncryptionKey,
} = require('./database-create-with-encryption-key');

require('yargs')
.demand(1)
Expand All @@ -172,6 +175,18 @@ require('yargs')
{},
opts => createDatabase(opts.instanceName, opts.databaseName, opts.projectId)
)
.command(
'createDatabaseWithEncryptionKey <instanceName> <databaseName> <projectId> <keyName>',
'Creates an example database using given encryption key in a Cloud Spanner instance.',
{},
opts =>
createDatabaseWithEncryptionKey(
opts.instanceName,
opts.databaseName,
opts.projectId,
opts.keyName
)
)
.command(
'addColumn <instanceName> <databaseName> <projectId>',
'Adds an example MarketingBudget column to an example Cloud Spanner table.',
Expand Down Expand Up @@ -201,6 +216,9 @@ require('yargs')
)
)
.example('node $0 createDatabase "my-instance" "my-database" "my-project-id"')
.example(
'node $0 createDatabaseWithEncryptionKey "my-instance" "my-database" "my-project-id" "key-name"'
)
.example('node $0 addColumn "my-instance" "my-database" "my-project-id"')
.example('node $0 queryNewColumn "my-instance" "my-database" "my-project-id"')
.example(
Expand Down
Loading

0 comments on commit 51cabc7

Please sign in to comment.