이 페이지에서는 Spanner에 고객 관리 암호화 키(CMEK)를 사용하는 방법을 설명합니다.
CMEK에 대한 자세한 내용은 고객 관리 암호화 키(CMEK)를 참조하세요.
CMEK 지원 데이터베이스 만들기
Cloud Key Management Service(Cloud KMS)에서 키를 만듭니다. Spanner는 다음을 지원합니다.
이 키는 Spanner 인스턴스와 동일한 위치에 있어야 합니다. 예를 들어 Spanner 인스턴스 구성이
us-west1
이면 키링 위치도us-west1
이어야 합니다.모든 Spanner 멀티 리전 인스턴스 구성에서 해당 키링 위치가 Cloud KMS에 있지는 않습니다. 그러한 Spanner 인스턴스에서는 CMEK 사용 데이터베이스를 만들지 못할 수 있습니다.
이미 올바른 위치에 Cloud KMS 키가 있으면 이 단계를 건너뛰어도 됩니다.
자세한 내용은 다음 리소스를 참조하세요.
Spanner에 키에 대한 액세스를 부여합니다.
Cloud Shell에서 서비스 에이전트를 만들어 표시하거나, 계정이 이미 있으면 표시합니다.
gcloud beta services identity create --service=spanner.googleapis.com \ --project=my_spanner_project
gcloud 베타 명령어 구성요소를 설치하라는 메시지가 표시되면
Y
를 입력합니다. 설치가 완료되면 명령어가 자동으로 다시 시작됩니다.gcloud services identity 명령어는 Spanner가 사용자 대신 Cloud KMS 키에 액세스하기 위해 사용할 수 있는 서비스 에이전트를 만들거나 가져옵니다.
서비스 계정 ID의 형식은 이메일 주소와 비슷합니다.
Service identity created: service-xxx@gcp-sa-spanner.iam.gserviceaccount.com
서비스 계정에
cloudkms.cryptoKeyEncrypterDecrypter
역할을 부여합니다.gcloud kms keys add-iam-policy-binding my_kms_key \ --location my_kms_key_location \ --keyring my_kms_key_ring \ --project=my_kms_project \ --member serviceAccount:service-xxx@gcp-sa-spanner.iam.gserviceaccount.com \ --role roles/cloudkms.cryptoKeyEncrypterDecrypter
다음과 같이 표시됩니다.
Updated IAM policy for key [my-kms-key]
이 역할은 Cloud KMS 키로 암호화 및 복호화할 수 있는 권한이 서비스 계정에 포함되도록 합니다. 자세한 내용은 Cloud KMS 권한 및 역할을 참조하세요.
데이터베이스를 만들고 Cloud KMS 키를 지정합니다.
콘솔
1. Google Cloud 콘솔에서 Spanner 인스턴스 페이지로 이동합니다.
2. 데이터베이스를 만들 인스턴스 이름을 클릭합니다.
3. 데이터베이스 만들기를 클릭하고 필수 필드를 입력합니다.
4. 암호화 옵션 표시를 클릭합니다.
5. 고객 관리 암호화 키(CMEK) 사용을 선택합니다.
6. 드롭다운 목록에서 키를 선택합니다.
키 목록은 현재 Google Cloud 프로젝트로 제한됩니다. 다른 Google Cloud 프로젝트의 키를 사용하려면 Google Cloud 콘솔 대신 gcloud를 사용하여 데이터베이스를 만듭니다.
데이터베이스가 생성되면 데이터베이스 세부정보 페이지를 확인하여 해당 데이터베이스가 CMEK 사용 데이터베이스인지 확인할 수 있습니다.
gcloud
gcloud spanner databases create example_db \ --project=my_spanner_project \ --instance=my_spanner_instance \ --ddl="CREATE TABLE Users (Id INT64 NOT NULL, FirstName STRING(100) NOT NULL, LastName STRING(100) NOT NULL,) PRIMARY KEY (Id)" \ --kms-project=my_kms_project \ --kms-location=my_kms_key_location \ --kms-keyring=my_kms_key_ring \ --kms-key=my_kms_key
데이터베이스가 CMEK 사용 데이터베이스인지 확인하려면 다음 안내를 따르세요.
gcloud spanner databases describe example_db \ --project=my_spanner_project \ --instance=my_spanner_instance
CMEK 사용 데이터베이스에는 이 예시에 표시된 것처럼
encryptionConfig
필드가 포함됩니다.encryptionConfig: kmsKeyName:projects/my-kms-project/locations/eur5/keyRings/my-kms-key-ring/cryptoKeys/my-kms-key name: projects/my-spanner-project/instances/my-instance/databases/my-db state: READY
C#
using Google.Cloud.Spanner.Admin.Database.V1; using Google.Cloud.Spanner.Common.V1; using System; using System.Threading.Tasks; public class CreateDatabaseWithEncryptionKeyAsyncSample { public async Task<Database> CreateDatabaseWithEncryptionKeyAsync(string projectId, string instanceId, string databaseId, CryptoKeyName kmsKeyName) { // Create a DatabaseAdminClient instance that can be used to execute a // CreateDatabaseRequest with custom encryption configuration options. DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create(); // Define create table statement for table #1. var createSingersTable = @"CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), ComposerInfo BYTES(MAX) ) PRIMARY KEY (SingerId)"; // Define create table statement for table #2. var createAlbumsTable = @"CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX) ) PRIMARY KEY (SingerId, AlbumId), INTERLEAVE IN PARENT Singers ON DELETE CASCADE"; // Create the CreateDatabase request with encryption configuration and execute it. var request = new CreateDatabaseRequest { ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId), CreateStatement = $"CREATE DATABASE `{databaseId}`", ExtraStatements = { createSingersTable, createAlbumsTable }, EncryptionConfig = new EncryptionConfig { KmsKeyNameAsCryptoKeyName = kmsKeyName, }, }; var operation = await databaseAdminClient.CreateDatabaseAsync(request); // Wait until the operation has finished. Console.WriteLine("Waiting for the operation to finish."); var completedResponse = await operation.PollUntilCompletedAsync(); if (completedResponse.IsFaulted) { Console.WriteLine($"Error while creating database: {completedResponse.Exception}"); throw completedResponse.Exception; } var database = completedResponse.Result; Console.WriteLine($"Database {database.Name} created with encryption key {database.EncryptionConfig.KmsKeyName}"); return database; } }
C++
Go
Java
Node.js
PHP
Python
Ruby
# project_id = "Your Google Cloud project ID" # instance_id = "Your Spanner instance ID" # database_id = "Your Spanner database ID" # kms_key_name = "Database eencryption KMS key" require "google/cloud/spanner" spanner = Google::Cloud::Spanner.new project: project_id instance = spanner.instance instance_id job = instance.create_database database_id, statements: [ "CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), SingerInfo BYTES(MAX) ) PRIMARY KEY (SingerId)", "CREATE TABLE Albums ( SingerId INT64 NOT NULL, AlbumId INT64 NOT NULL, AlbumTitle STRING(MAX) ) PRIMARY KEY (SingerId, AlbumId), INTERLEAVE IN PARENT Singers ON DELETE CASCADE" ], encryption_config: { kms_key_name: kms_key_name } puts "Waiting for create database operation to complete" job.wait_until_done! database = job.database puts "Database #{database.database_id} created with encryption key #{database.encryption_config.kms_key_name}"
사용 중인 키 버전 보기
키 버전에 대한 정보는 데이터베이스의 encryption_info
필드에서 비롯됩니다.
데이터베이스의 키 버전이 변경될 때 변경사항은 encryption_info
에 즉시 전파되지 않습니다. 변경사항이 정보 필드에 반영되기 위해서는 지연이 필요할 수 있습니다.
콘솔
암호화 정보는 데이터베이스 세부정보 페이지에 표시됩니다.
gcloud
databases describe
또는 databases list
를 호출하여 데이터베이스의 encryption_info
를 가져옵니다. 예를 들면 다음과 같습니다.
gcloud spanner databases describe example_db \
--project=my_spanner_project \
--instance=my_spanner_instance
출력은 다음과 같습니다.
name: projects/my-project/instances/test-instance/databases/example-db
encryptionConfig:
kmsKeyName: projects/google.com:cloud-spanner-demo/locations/us-central1/keyRings/cmek_demo/cryptoKeys/backup-key
encryptionInfo:
encryptionType: CUSTOMER_MANAGED_ENCRYPTION
키 사용 중지
각 키 버전에 대해 이 안내에 따라 사용 중인 키 버전을 사용 중지합니다.
변경사항이 적용될 때까지 기다립니다. 키를 사용 중지하면 변경사항이 전파될 때까지 최대 3시간까지 걸릴 수 있습니다.
데이터에 더 이상 액세스할 수 없는지 확인합니다.
gcloud spanner databases execute-sql example_db \ --project=my_spanner_project \ --instance=my_spanner_instance \ --sql='SELECT * FROM Users'
다음 오류가 표시됩니다.
KMS key required by the Spanner resource is not accessible.
키 사용 설정
각 키 버전에 대해 이 안내에 따라 데이터베이스에서 현재 사용 중인 키 버전을 사용 설정합니다.
변경사항이 적용될 때까지 기다립니다. 키를 사용 설정하면 변경사항이 전파될 때까지 최대 3시간까지 걸릴 수 있습니다.
데이터에 액세스할 수 있는지 확인합니다.
gcloud spanner databases execute-sql example_db \ --project=my_spanner_project \ --instance=my_spanner_instance \ --sql='SELECT * FROM Users'
변경사항이 적용되었으면 명령어가 성공적으로 실행됩니다.
데이터베이스 백업
기본적으로 데이터베이스에서 생성된 백업에는 데이터베이스 자체와 동일한 암호화 구성이 사용됩니다. 선택적으로 백업에 다른 암호화 구성을 지정할 수 있습니다.
백업을 만들려면 다음 안내를 따르세요.
콘솔
Google Cloud 콘솔에서 데이터베이스 세부정보 페이지로 이동합니다.
백업/복원 탭에서 만들기를 클릭합니다.
백업 이름을 입력하고 만료 상태를 선택합니다.
고객 관리 암호화 키(CMEK) 사용을 선택하고 드롭다운 목록에서 키를 선택합니다.
만들기를 클릭합니다.
백업 테이블에 각 백업에 대한 암호화 정보가 표시됩니다.
gcloud
gcloud spanner backups create my_backup \
--project=my_spanner_project \
--instance=my_spanner_instance \
--database=example_db \
--retention-period=1y \
--encryption-type=customer_managed_encryption \
--kms-project=my_kms_project \
--kms-location=my_kms_key_location \
--kms-keyring=my_kms_key_ring \
--kms-key=my_kms_key
--async
생성된 백업이 CMEK로 암호화되었는지 확인하려면 다음 안내를 따르세요.
gcloud spanner backups describe my_backup \
--project=my_spanner_project \
--instance=my_spanner_instance
C#
using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using Google.Protobuf.WellKnownTypes;
using System;
using System.Threading.Tasks;
public class CreateBackupWithEncryptionKeyAsyncSample
{
public async Task<Backup> CreateBackupWithEncryptionKeyAsync(string projectId, string instanceId, string databaseId, string backupId, CryptoKeyName kmsKeyName)
{
// Create a DatabaseAdminClient instance.
DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();
// Create the CreateBackupRequest with encryption configuration.
CreateBackupRequest request = new CreateBackupRequest
{
ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId),
BackupId = backupId,
Backup = new Backup
{
DatabaseAsDatabaseName = DatabaseName.FromProjectInstanceDatabase(projectId, instanceId, databaseId),
ExpireTime = DateTime.UtcNow.AddDays(14).ToTimestamp(),
},
EncryptionConfig = new CreateBackupEncryptionConfig
{
EncryptionType = CreateBackupEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,
KmsKeyNameAsCryptoKeyName = kmsKeyName,
},
};
// Execute the CreateBackup request.
var operation = await databaseAdminClient.CreateBackupAsync(request);
Console.WriteLine("Waiting for the operation to finish.");
// Poll until the returned long-running operation is complete.
var completedResponse = await operation.PollUntilCompletedAsync();
if (completedResponse.IsFaulted)
{
Console.WriteLine($"Error while creating backup: {completedResponse.Exception}");
throw completedResponse.Exception;
}
var backup = completedResponse.Result;
Console.WriteLine($"Backup {backup.Name} of size {backup.SizeBytes} bytes " +
$"was created at {backup.CreateTime} " +
$"using encryption key {kmsKeyName}");
return backup;
}
}
C++
Go
Java
Node.js
PHP
Python
Ruby
# project_id = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"
# backup_id = "Your Spanner backup ID"
# kms_key_name = "Your backup encryption database KMS key"
require "google/cloud/spanner"
spanner = Google::Cloud::Spanner.new project: project_id
client = spanner.client instance_id, database_id
instance = spanner.instance instance_id
database = instance.database database_id
expire_time = Time.now + 14 * 24 * 3600 # 14 days from now
encryption_config = {
encryption_type: :CUSTOMER_MANAGED_ENCRYPTION,
kms_key_name: kms_key_name
}
job = database.create_backup backup_id, expire_time, version_time: version_time, encryption_config: encryption_config
puts "Backup operation in progress"
job.wait_until_done!
backup = instance.backup backup_id
puts "Backup #{backup.backup_id} of size #{backup.size_in_bytes} bytes was created at #{backup.create_time} using encryption key #{kms_key_name}"
백업에서 복원
기본적으로 백업에서 복원된 데이터베이스에는 백업 자체와 동일한 암호화 구성이 사용됩니다. 하지만 복원된 데이터베이스에 대해 다른 암호화 구성을 지정하여 이 동작을 재정의할 수 있습니다. 백업이 CMEK로 보호되는 경우 백업을 만들기 위해 사용된 키 버전을 복호화 작업에 사용할 수 있어야 합니다.
데이터베이스를 복원하려면:
콘솔
Cloud 콘솔에서 인스턴스 세부정보 페이지로 이동합니다.
백업/복원 탭에서 백업을 선택하고 복원을 클릭합니다.
복원할 인스턴스를 선택하고 복원된 데이터베이스의 이름을 지정합니다.
복원된 데이터베이스에 CMEK를 사용하려면 고객 관리 암호화 키(CMEK) 사용을 선택하고 드롭다운 목록에서 키를 선택합니다.
gcloud
gcloud spanner databases restore --async \
--project=my_spanner_project \
--destination-instance=destination_instance \
--destination-database=example_db_restored \
--source-instance=my_spanner_instance \
--source-backup=my_backup
복원된 데이터베이스가 CMEK로 암호화되었는지 확인합니다.
gcloud spanner databases describe example_db_restored \
--project=my_spanner_project \
--instance=destination_instance
자세한 내용은 백업에서 데이터베이스 복원을 참조하세요.
C#
using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using System;
using System.Threading.Tasks;
public class RestoreDatabaseWithEncryptionAsyncSample
{
public async Task<Database> RestoreDatabaseWithEncryptionAsync(string projectId, string instanceId, string databaseId, string backupId, CryptoKeyName kmsKeyName)
{
// Create a DatabaseAdminClient instance.
DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();
// Create the RestoreDatabaseRequest with encryption configuration.
RestoreDatabaseRequest request = new RestoreDatabaseRequest
{
ParentAsInstanceName = InstanceName.FromProjectInstance(projectId, instanceId),
DatabaseId = databaseId,
BackupAsBackupName = BackupName.FromProjectInstanceBackup(projectId, instanceId, backupId),
EncryptionConfig = new RestoreDatabaseEncryptionConfig
{
EncryptionType = RestoreDatabaseEncryptionConfig.Types.EncryptionType.CustomerManagedEncryption,
KmsKeyNameAsCryptoKeyName = kmsKeyName,
}
};
// Execute the RestoreDatabase request.
var operation = await databaseAdminClient.RestoreDatabaseAsync(request);
Console.WriteLine("Waiting for the operation to finish.");
// Poll until the returned long-running operation is complete.
var completedResponse = await operation.PollUntilCompletedAsync();
if (completedResponse.IsFaulted)
{
Console.WriteLine($"Error while restoring database: {completedResponse.Exception}");
throw completedResponse.Exception;
}
var database = completedResponse.Result;
var restoreInfo = database.RestoreInfo;
Console.WriteLine($"Database {restoreInfo.BackupInfo.SourceDatabase} " +
$"restored to {database.Name} " +
$"from backup {restoreInfo.BackupInfo.Backup} " +
$"using encryption key {database.EncryptionConfig.KmsKeyName}");
return database;
}
}
C++
Go
Java
Node.js
PHP
Python
Ruby
# project_id = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID of where to restore"
# backup_id = "Your Spanner backup ID"
# kms_key_name = "Your backup encryption database KMS key"
require "google/cloud/spanner"
spanner = Google::Cloud::Spanner.new project: project_id
instance = spanner.instance instance_id
backup = instance.backup backup_id
encryption_config = {
encryption_type: :CUSTOMER_MANAGED_ENCRYPTION,
kms_key_name: kms_key_name
}
job = backup.restore database_id, encryption_config: encryption_config
puts "Waiting for restore backup operation to complete"
job.wait_until_done!
database = job.database
restore_info = database.restore_info
puts "Database #{restore_info.backup_info.source_database_id} was restored to #{database.database_id} from backup #{restore_info.backup_info.backup_id} using encryption key #{database.encryption_config.kms_key_name}"
Cloud KMS 키의 감사 로그 보기
프로젝트에서 Cloud KMS API에 대해 로깅이 사용 설정되었는지 확인합니다.
Cloud 콘솔의 로그 탐색기로 이동합니다.
쿼리 빌더에 다음 줄을 추가하여 로그 항목을 Cloud KMS로 제한합니다.
resource.type="cloudkms_cryptokey" resource.labels.location="my_kms_key_location" resource.labels.key_ring_id="my_kms_key_ring" resource.labels.crypto_key_id="my_kms_key"
일반 작업 아래에서 암호화 및 복호화 작업이
INFO
심각도로 로깅됩니다. 이러한 항목은 Spanner 인스턴스의 영역이 약 5분 간격으로 Cloud KMS 키를 폴링할 때 로깅됩니다.Spanner가 키에 액세스하지 못하면 작업이
ERROR
로 로깅됩니다.