문서 메뉴
문서 홈
/
MongoDB 매뉴얼
/ / / / /

명시적 암호화 사용

이 페이지의 내용

  • 개요
  • 시작하기 전에
  • 절차
  • 고객 마스터 키 생성
  • 키 볼트 collection에 고유 인덱스 만들기
  • 데이터 암호화 키 및 암호화된 collection 만들기
  • 암호화된 읽기 및 쓰기를 위한 MongoClient 구성
  • 암호화된 필드가 있는 문서 삽입하기
  • 암호화된 필드로 문서 검색하기
  • 자세히 알아보기

이 가이드에서는 명시적 암호화와 MongoDB 드라이버를 사용하여 문서를 암호화하는 방법을 보여줍니다.

이 가이드를 완료한 후에는 명시적 암호화를 사용하여 문서의 필드를 암호화하도록 드라이버를 구성할 수 있을 것입니다. 이러한 지식이 있으면 명시적 암호화를 사용하는 클라이언트 애플리케이션을 만들 수 있어야 합니다. 자동 암호 해독 포함.

중요

프로덕션 환경에서 이 샘플 애플리케이션을 사용하지 마세요.

이 튜토리얼의 지침에는 안전하지 않은 환경에 암호화 키를 저장하는 방법이 포함되어 있으므로 이 애플리케이션의 수정되지 않은 버전을 프로덕션 환경에서 사용해서는 안 됩니다. 프로덕션 환경에서 이 애플리케이션을 사용하면 암호화 키에 무단으로 액세스하거나 데이터 암호 해독에 필요한 키가 손실될 위험이 있습니다. 이 튜토리얼의 목적은 키 관리 시스템을 설정할 필요 없이 Queryable Encryption을 사용하는 방법을 설명하는 것입니다.

키 관리 시스템을 사용하여 프로덕션 환경에 암호화 키를 안전하게 저장할 수 있습니다. KMS 는 암호화 키를 안전하게 저장하고 managed 원격 서비스입니다. KMS 를 사용하는 Queryable Encryption 지원 애플리케이션을 설정하는 방법을 알아보려면 Queryable Encryption 튜토리얼을 참조하세요.

이 가이드의 코드를 완료하고 실행하려면 설치 요구 사항 페이지에 표시된 대로 개발 환경을 설정해야 합니다.

참조: 전체 적용

이 가이드에서 만든 애플리케이션의 전체 코드를 보려면 선호하는 MongoDB 드라이버에 해당하는 탭을 선택하고 제공된 링크를 따라가세요:

Node.js 애플리케이션 완성

1

Queryable Encryption을 수행하려면 고객 마스터 키(CMK)를 생성해야 합니다.

96바이트 고객 마스터 키를 생성하여 master-key.txt 파일에 저장합니다.

using (var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create())
{
var bytes = new byte[96];
randomNumberGenerator.GetBytes(bytes);
var localMasterKeyBase64Write = Convert.ToBase64String(bytes);
File.WriteAllText("master-key.txt", localMasterKeyBase64Write);
}
func localMasterKey() []byte {
key := make([]byte, 96)
if _, err := rand.Read(key); err != nil {
log.Fatalf("Unable to create a random 96 byte data key: %v", err)
}
if err := ioutil.WriteFile("master-key.txt", key, 0644); err != nil {
log.Fatalf("Unable to write key to file: %v", err)
}
return key
}
byte[] localMasterKeyWrite = new byte[96];
new SecureRandom().nextBytes(localMasterKeyWrite);
try (FileOutputStream stream = new FileOutputStream("master-key.txt")) {
stream.write(localMasterKeyWrite);
}
const fs = require("fs");
const crypto = require("crypto");
try {
fs.writeFileSync("master-key.txt", crypto.randomBytes(96));
} catch (err) {
console.error(err);
}
path = "master-key.txt"
file_bytes = os.urandom(96)
with open(path, "wb") as f:
f.write(file_bytes)

경고

프로덕션 환경에서 로컬 키 파일을 사용하지 마세요.

파일 시스템의 로컬 키 파일은 안전하지 않으므로 프로덕션에 권장되지 않습니다 . 대신 원격 키 관리 시스템 에 고객 마스터 키를 저장해야 합니다. (KMS ).

Queryable Encryption 구현에서 원격 KMS 를 사용하는 방법을 알아보려면 튜토리얼 가이드를 참조하세요.

명령줄에서 고객 마스터 키 생성

Unix shell 또는 PowerShell에서 고객 마스터 키 를 생성하려면 다음 명령을 사용합니다.

  • Unix shell:

    echo $(head -c 96 /dev/urandom | base64 | tr -d '\n')
  • PowerShell:

    $r=[byte[]]::new(64);$g=[System.Security.Cryptography.RandomNumberGenerator]::Create();$g.GetBytes($r);[Convert]::ToBase64String($r)

이전 명령의 출력을 customer-master-key.txt 파일에 저장합니다.

참조: 코드 완성

2

encryption.__keyVault 네임스페이스의 keyAltNames 필드에 고유 인덱스를 만듭니다.

선호하는 MongoDB 드라이버에 해당하는 탭을 선택합니다:

var connectionString = "<Your MongoDB URI>";
var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
var keyVaultClient = new MongoClient(connectionString);
var indexOptions = new CreateIndexOptions<BsonDocument>
{
Unique = true,
PartialFilterExpression = new BsonDocument
{{"keyAltNames", new BsonDocument {{"$exists", new BsonBoolean(true)}}}}
};
var builder = Builders<BsonDocument>.IndexKeys;
var indexKeysDocument = builder.Ascending("keyAltNames");
var indexModel = new CreateIndexModel<BsonDocument>(indexKeysDocument, indexOptions);
var keyVaultDatabase = keyVaultClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName);
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
keyVaultDatabase.DropCollection(keyVaultNamespace.CollectionName);
var keyVaultCollection = keyVaultDatabase.GetCollection<BsonDocument>(keyVaultNamespace.CollectionName);
keyVaultCollection.Indexes.CreateOne(indexModel);

중요

go build 또는 go run 을 사용하여 이 가이드의 Golang 코드를 빌드하거나 실행할 때는 항상 cse 빌드 제약 조건을 포함하여 Queryable Encryption을 활성화하세요. 빌드 제약 조건을 포함하는 예는 다음 셸 명령을 참조하세요.

go run -tags cse make-data-key.go
uri := "<Your MongoDB URI>"
keyVaultClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
return fmt.Errorf("Connect error for regular client: %v", err)
}
defer func() {
_ = keyVaultClient.Disconnect(context.TODO())
}()
keyVaultDb := "encryption"
keyVaultColl := "__keyVault"
keyVaultNamespace := keyVaultDb + "." + keyVaultColl
keyVaultIndex := mongo.IndexModel{
Keys: bson.D{{"keyAltNames", 1}},
Options: options.Index().
SetUnique(true).
SetPartialFilterExpression(bson.D{
{"keyAltNames", bson.D{
{"$exists", true},
}},
}),
}
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
if err = keyVaultClient.Database(keyVaultDb).Collection(keyVaultColl).Drop(context.TODO()); err != nil {
log.Fatalf("Collection.Drop error: %v", err)
}
_, err = keyVaultClient.Database(keyVaultDb).Collection(keyVaultColl).Indexes().CreateOne(context.TODO(), keyVaultIndex)
if err != nil {
panic(err)
}
String keyVaultDb = "encryption";
String keyVaultColl = "__keyVault";
MongoClient keyVaultClient = MongoClients.create(connectionString);
String encryptedDbName = "medicalRecords";
String encryptedCollName = "patients";
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl).drop();
MongoCollection keyVaultCollection = keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl);
IndexOptions indexOpts = new IndexOptions().partialFilterExpression(new BsonDocument("keyAltNames", new BsonDocument("$exists", new BsonBoolean(true) ))).unique(true);
keyVaultCollection.createIndex(new BsonDocument("keyAltNames", new BsonInt32(1)), indexOpts);
keyVaultClient.close();
const uri = "<Your Connection String>";
const keyVaultClient = new MongoClient(uri);
await keyVaultClient.connect();
const keyVaultDB = keyVaultClient.db(keyVaultDatabase);
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
await keyVaultDB.dropDatabase();
const keyVaultColl = keyVaultDB.collection(keyVaultCollection);
await keyVaultColl.createIndex(
{ keyAltNames: 1 },
{
unique: true,
partialFilterExpression: { keyAltNames: { $exists: true } },
}
);
connection_string = "<your connection string here>"
key_vault_coll = "__keyVault"
key_vault_db = "encryption"
key_vault_namespace = f"{key_vault_db}.{key_vault_coll}"
key_vault_client = MongoClient(connection_string)
# Drop the Key Vault Collection in case you created this collection
# in a previous run of this application.
key_vault_client.drop_database(key_vault_db)
key_vault_client[key_vault_db][key_vault_coll].create_index(
[("keyAltNames", ASCENDING)],
unique=True,
partialFilterExpression={"keyAltNames": {"$exists": True}},
)
3
1

이 가이드의 고객 마스터 키 생성 단계에서 생성한 고객 마스터 키 파일의 내용을 조회합니다.

고객 마스터 키 값을 KMS 제공자 설정으로 전달합니다. 클라이언트는 이러한 설정을 사용하여 고객 마스터 키 를 검색합니다. 제공자 이름을 local 로 설정하여 로컬 키 제공자를 사용하고 있음을 드라이버에 알립니다.

선호하는 MongoDB 드라이버에 해당하는 탭을 선택합니다:

var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>();
const string provider = "local";
var localMasterKeyBase64Read = File.ReadAllText("master-key.txt");
var localMasterKeyBytes = Convert.FromBase64String(localMasterKeyBase64Read);
var localOptions = new Dictionary<string, object>
{
{"key", localMasterKeyBytes}
};
kmsProviders.Add(provider, localOptions);
key, err := ioutil.ReadFile("master-key.txt")
if err != nil {
log.Fatalf("Could not read the key from master-key.txt: %v", err)
}
provider := "local"
kmsProviders := map[string]map[string]interface{}{"local": {"key": key}}
String kmsProvider = "local";
String path = "master-key.txt";
byte[] localMasterKeyRead = new byte[96];
try (FileInputStream fis = new FileInputStream(path)) {
if (fis.read(localMasterKeyRead) < 96)
throw new Exception("Expected to read 96 bytes from file");
}
Map<String, Object> keyMap = new HashMap<String, Object>();
keyMap.put("key", localMasterKeyRead);
Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
kmsProviders.put("local", keyMap);
const provider = "local";
const path = "./master-key.txt";
// WARNING: Do not use a local key file in a production application
const localMasterKey = fs.readFileSync(path);
const kmsProviders = {
local: {
key: localMasterKey,
},
};
provider = "local"
path = "./master-key.txt"
# WARNING: Do not use a local key file in a production application
with open(path, "rb") as f:
local_master_key = f.read()
kms_providers = {
"local": {
"key": local_master_key # local_master_key variable from the previous step
},
}
2

MongoDB 연결 문자열과 키 볼트 컬렉션 네임스페이스를 사용하여 클라이언트를 구성하고 데이터 암호화 키를 만듭니다.

참고

키 볼트 컬렉션 네임스페이스 권한

이 튜토리얼을 완료하려면 애플리케이션에서 MongoDB에 연결하는 데 사용하는 데이터베이스 사용자에게 다음 네임스페이스에 대한 dbAdmin 권한이 있어야 합니다.

  • encryption.__keyVault

  • medicalRecords 데이터베이스

var clientEncryptionOptions = new ClientEncryptionOptions(
keyVaultClient,
keyVaultNamespace,
kmsProviders: kmsProviders
);
var clientEncryption = new ClientEncryption(clientEncryptionOptions);
var dataKeyOptions1 = new DataKeyOptions(alternateKeyNames: new List<string> { "dataKey1" });
var dataKeyOptions2 = new DataKeyOptions(alternateKeyNames: new List<string> { "dataKey2" });
BsonBinaryData CreateKeyGetID(DataKeyOptions options)
{
var dateKeyGuid = clientEncryption.CreateDataKey(provider, options, CancellationToken.None);
return new BsonBinaryData(dateKeyGuid, GuidRepresentation.Standard);
}
var dataKeyId1 = CreateKeyGetID(dataKeyOptions1);
var dataKeyId2 = CreateKeyGetID(dataKeyOptions2);
var dataKeyId3 = CreateKeyGetID(dataKeyOptions3);
var dataKeyId4 = CreateKeyGetID(dataKeyOptions4);
clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(keyVaultNamespace).
SetKmsProviders(kmsProviders)
clientEnc, err := mongo.NewClientEncryption(keyVaultClient, clientEncryptionOpts)
if err != nil {
return fmt.Errorf("NewClientEncryption error %v", err)
}
defer func() {
_ = clientEnc.Close(context.TODO())
}()
dataKeyOpts1 := options.DataKey().
SetKeyAltNames([]string{"demoDataKey1"})
dataKeyID1, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts1)
if err != nil {
return fmt.Errorf("create data key error %v", err)
}
dataKeyOpts2 := options.DataKey().
SetKeyAltNames([]string{"demoDataKey2"})
dataKeyID2, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts2)
if err != nil {
return fmt.Errorf("create data key error %v", err)
}
String keyVaultNamespace = keyVaultDb + "." + keyVaultColl;
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
.keyVaultMongoClientSettings(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.build())
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.build();
ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
List<String> keyAlts1 = new ArrayList<String>();
keyAlts1.add("dataKey1");
BsonBinary dataKeyId1 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions()
.keyAltNames(keyAlts1));
List<String> keyAlts2 = new ArrayList<String>();
keyAlts2.add("dataKey2");
BsonBinary dataKeyId2 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions()
.keyAltNames(keyAlts2));
const clientEnc = new ClientEncryption(keyVaultClient, {
keyVaultNamespace: keyVaultNamespace,
kmsProviders: kmsProviders,
});
const dek1 = await clientEnc.createDataKey(provider, {
keyAltNames: ["dataKey1"],
});
const dek2 = await clientEnc.createDataKey(provider, {
keyAltNames: ["dataKey2"],
});
client = MongoClient(connection_string)
client_encryption = ClientEncryption(
kms_providers, # pass in the kms_providers variable from the previous step
key_vault_namespace,
client,
CodecOptions(uuid_representation=STANDARD),
)
data_key_id_1 = client_encryption.create_data_key(provider, key_alt_names=["dataKey1"])
data_key_id_2 = client_encryption.create_data_key(provider, key_alt_names=["dataKey2"])
3

Queryable Encryption이 활성화된 MongoClient 인스턴스를 사용하여 필드를 암호화하고 collection을 생성합니다.

var encryptedCollectionNamespace = CollectionNamespace.FromFullName("medicalRecords.patients");
var encryptedFieldsMap = new Dictionary<string, BsonDocument>
{
{
encryptedCollectionNamespace.FullName, new BsonDocument
{
{
"fields", new BsonArray
{
new BsonDocument
{
{"keyId", dataKeyId1},
{"path", new BsonString("patientId")},
{"bsonType", new BsonString("int")},
{
"queries", new BsonDocument
{
{"queryType", new BsonString("equality")}
}
}
},
new BsonDocument
{
{"keyId", dataKeyId2},
{"path", new BsonString("medications")},
{"bsonType", new BsonString("array")},
},
}
}
}
}
};
var extraOptions = new Dictionary<string, object>()
{
{ "cryptSharedLibPath", "<path to crypt_shared library>" },
};
var autoEncryptionOptions = new AutoEncryptionOptions(
keyVaultNamespace,
kmsProviders,
encryptedFieldsMap: encryptedFieldsMap,
extraOptions: extraOptions);
var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
clientSettings.AutoEncryptionOptions = autoEncryptionOptions;
var secureClient = new MongoClient(clientSettings);
var encryptedDatabase = secureClient.GetDatabase(encryptedCollectionNamespace.DatabaseNamespace.DatabaseName);
// Drop the encrypted collection in case you created this collection
// in a previous run of this application.
encryptedDatabase.DropCollection(encryptedCollectionNamespace.CollectionName);
encryptedDatabase.CreateCollection(encryptedCollectionNamespace.CollectionName);
Console.WriteLine("Created encrypted collection!");
dbName := "medicalRecords"
collName := "patients"
encNamespace := (dbName + "." + collName)
encryptedFieldsMap := bson.M{
encNamespace: bson.M{
"fields": []bson.M{
{
"path": "patientId",
"bsonType": "int",
"keyId": dataKeyID1,
"queries": []bson.M{
{
"queryType": "equality",
},
},
},
{
"path": "medications",
"bsonType": "array",
"keyId": dataKeyID2,
},
},
},
}
extraOptions := map[string]interface{}{
"cryptSharedLibPath": "<Your Crypt Shared lib Path>",
}
autoEncryptionOpts := options.AutoEncryption().
SetKmsProviders(kmsProviders).
SetKeyVaultNamespace(keyVaultNamespace).
SetEncryptedFieldsMap(encryptedFieldsMap).
SetExtraOptions(extraOptions)
secureClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri).SetAutoEncryptionOptions(autoEncryptionOpts))
if err != nil {
return fmt.Errorf("Connect error for encrypted client: %v", err)
}
defer func() {
_ = secureClient.Disconnect(context.TODO())
}()
// Drop the encrypted collection in case you created this collection
// in a previous run of this application.
if err = secureClient.Database(dbName).Collection(collName).Drop(context.TODO()); err != nil {
log.Fatalf("Collection.Drop error: %v", err)
}
err = secureClient.Database(dbName).CreateCollection(context.TODO(), collName)
if err != nil {
return fmt.Errorf("Error creating collection: %v", err)
}
String encryptedNameSpace = encryptedDbName + "." + encryptedCollName;
BsonDocument encFields = new BsonDocument().append("fields",
new BsonArray(Arrays.asList(
new BsonDocument().append("keyId", dataKeyId1)
.append("path", new BsonString("patientId"))
.append("bsonType", new BsonString("int"))
.append("queries", new BsonDocument().append("queryType", new BsonString("equality"))),
new BsonDocument().append("keyId", dataKeyId2)
.append("path", new BsonString("medications"))
.append("bsonType", new BsonString("array")),
)));
Map<String, BsonDocument> encryptedFieldsMap = new HashMap<String, BsonDocument>();
encryptedFieldsMap.put(encryptedNameSpace, encFields);
Map<String, Object> extraOptions = new HashMap<String, Object>();
extraOptions.put("cryptSharedLibPath", "<path to crypt_shared>");
MongoClientSettings clientSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.autoEncryptionSettings(AutoEncryptionSettings.builder()
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.encryptedFieldsMap(encryptedFieldsMap)
.extraOptions(extraOptions)
.build())
.build();
MongoClient mongoClientSecure = MongoClients.create(clientSettings);
MongoDatabase encDb = mongoClientSecure.getDatabase(encryptedDbName);
// Drop the encrypted collection in case you created this collection
// in a previous run of this application.
encDb.getCollection(encryptedCollName).drop();
encDb.createCollection(encryptedCollName);
const encryptedFieldsMap = {
[`${secretDB}.${secretCollection}`]: {
fields: [
{
keyId: dek1,
path: "patientId",
bsonType: "int",
queries: { queryType: "equality" },
},
{
keyId: dek2,
path: "medications",
bsonType: "array",
},
],
},
};
const extraOptions = {
cryptSharedLibPath: "<path to FLE Shared Library>",
};
const encClient = new MongoClient(uri, {
autoEncryption: {
keyVaultNamespace,
kmsProviders,
extraOptions,
encryptedFieldsMap,
},
});
await encClient.connect();
const newEncDB = encClient.db(secretDB);
// Drop the encrypted collection in case you created this collection
// in a previous run of this application.
await newEncDB.dropDatabase();
await newEncDB.createCollection(secretCollection);
console.log("Created encrypted collection!");
encrypted_db_name = "medicalRecords"
encrypted_coll_name = "patients"
encrypted_fields_map = {
f"{encrypted_db_name}.{encrypted_coll_name}": {
"fields": [
{
"keyId": data_key_id_1,
"path": "patientId",
"bsonType": "int",
"queries": {"queryType": "equality"},
},
{
"keyId": data_key_id_2,
"path": "medications",
"bsonType": "array",
},
],
},
}
key_vault_namespace = "encryption.__keyVault"
auto_encryption = AutoEncryptionOpts(
kms_providers,
key_vault_namespace,
encrypted_fields_map=encrypted_fields_map,
crypt_shared_lib_path="<path to FLE Shared Library>",
)
secure_client = MongoClient(connection_string, auto_encryption_opts=auto_encryption)
# Drop the encrypted collection in case you created this collection
# in a previous run of this application.
secure_client.drop_database(encrypted_db_name)
encrypted_db = secure_client[encrypted_db_name]
encrypted_db.create_collection(encrypted_coll_name)
print("Created encrypted collection!")

이 섹션의 코드 출력은 다음과 유사해야 합니다.

Created encrypted collection!

참조: 코드 완성

4
1

키 볼트 collection 네임스페이스로 encryption.__keyVault 을 지정합니다.

var connectionString = "<Your MongoDB URI>";
var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
var coll = "patients";
var db = "medicalRecords";
keyVaultColl := "__keyVault"
keyVaultDb := "encryption"
keyVaultNamespace := keyVaultDb + "." + keyVaultColl
dbName := "medicalRecords"
collName := "patients"
String db = "medicalRecords";
String coll = "patients";
String keyVaultDb = "encryption";
String keyVaultColl = "__keyVault";
String keyVaultNamespace = String.format("%1$s.%2$s", keyVaultDb, keyVaultColl);
String connectionString = "<Your MongoDB URI>";
const eDB = "encryption";
const eKV = "__keyVault";
const keyVaultNamespace = `${eDB}.${eKV}`;
const secretDB = "medicalRecords";
const secretCollection = "patients";
key_vault_namespace = "encryption.__keyVault"
key_vault_db_name, key_vault_coll_name = key_vault_namespace.split(".", 1)
2

KMS 제공자를 지정하고 고객 마스터 키를 인라인으로 지정합니다.

var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>();
const string provider = "local";
const string localMasterKeyPath = "master-key.txt";
var localMasterKeyBase64Read = File.ReadAllText(localMasterKeyPath);
var localMasterKeyBytes = Convert.FromBase64String(localMasterKeyBase64Read);
var localOptions = new Dictionary<string, object>
{
{"key", localMasterKeyBytes}
};
kmsProviders.Add(provider, localOptions);
key, err := ioutil.ReadFile("master-key.txt")
if err != nil {
log.Fatalf("Could not read the key from master-key.txt: %v", err)
}
kmsProviders := map[string]map[string]interface{}{"local": {"key": key}}
String kmsProvider = "local";
String path = "master-key.txt";
byte[] localMasterKeyRead = new byte[96];
try (FileInputStream fis = new FileInputStream(path)) {
if (fis.read(localMasterKeyRead) < 96)
throw new Exception("Expected to read 96 bytes from file");
}
Map<String, Object> keyMap = new HashMap<>();
keyMap.put("key", localMasterKeyRead);
Map<String, Map<String, Object>> kmsProviders = new HashMap<>();
kmsProviders.put(kmsProvider, keyMap);
const fs = require("fs");
const path = "./master-key.txt";
// WARNING: Do not use a local key file in a production application
const localMasterKey = fs.readFileSync(path);
const kmsProviders = {
local: {
key: localMasterKey,
},
};
path = "./master-key.txt"
with open(path, "rb") as f:
local_master_key = f.read()
kms_providers = {
"local": {
"key": local_master_key # local_master_key variable from the previous step
},
}
3

이 가이드의 데이터 암호화 키 생성 단계에서 생성된 데이터 암호화 키를 조회합니다 .

var regularClient = new MongoClient(connectionString);
var keyVaultCollection = regularClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName)
.GetCollection<BsonDocument>(keyVaultNamespace.CollectionName);
Guid GetKeyId(string altName)
{
var filter = Builders<BsonDocument>.Filter.Eq<BsonString>("keyAltNames", altName);
return keyVaultCollection.Find(filter).First<BsonDocument>()["_id"].AsGuid;
}
var dataKeyId1 = GetKeyId("dataKey1");
var dataKeyId2 = GetKeyId("dataKey2");
uri := "<Your MongoDB URI>"
regularClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri))
if err != nil {
panic(fmt.Errorf("Client connect error %v", err))
}
var foundDoc1 bson.M
err = regularClient.Database(keyVaultDb).Collection(keyVaultColl).FindOne(context.TODO(), bson.D{{"keyAltNames", "demoDataKey1"}}).Decode(&foundDoc1)
if err != nil {
panic(err)
}
var dataKeyID1 = foundDoc1["_id"].(primitive.Binary)
var foundDoc2 bson.M
err = regularClient.Database(keyVaultDb).Collection(keyVaultColl).FindOne(context.TODO(), bson.D{{"keyAltNames", "demoDataKey2"}}).Decode(&foundDoc2)
if err != nil {
panic(err)
}
var dataKeyID2 = foundDoc2["_id"].(primitive.Binary)
MongoClient client = MongoClients.create(connectionString);
MongoCollection<Document> keyVaultClient = client.getDatabase(keyVaultDb).getCollection(keyVaultColl);
BsonBinary dataKeyId1 = new BsonBinary(BsonBinarySubType.UUID_STANDARD, keyVaultClient.find(eq("keyAltNames", "dataKey1")).first().get("_id", Binary.class).getData());
BsonBinary dataKeyId2 = new BsonBinary(BsonBinarySubType.UUID_STANDARD, keyVaultClient.find(eq("keyAltNames", "dataKey2")).first().get("_id", Binary.class).getData());
const uri = "<Your MongoDB URI>";
const unencryptedClient = new MongoClient(uri);
await unencryptedClient.connect();
const keyVaultClient = unencryptedClient.db(eDB).collection(eKV);
const dek1 = await keyVaultClient.findOne({ keyAltNames: "dataKey1" });
const dek2 = await keyVaultClient.findOne({ keyAltNames: "dataKey2" });
connection_string = "<your connection string here>"
client = MongoClient(connection_string)
key_vault = client[key_vault_db_name][key_vault_coll_name]
data_key_id_1 = key_vault.find_one({"keyAltNames": "dataKey1"})["_id"]
data_key_id_2 = key_vault.find_one({"keyAltNames": "dataKey2"})["_id"]
4
var extraOptions = new Dictionary<string, object>()
{
{"cryptSharedLibPath", "<path to crypt_shared library>"},
};
extraOptions := map[string]interface{}{
"cryptSharedLibPath": "<path to crypt_shared library>",
}
Map<String, Object> extraOptions = new HashMap<>();
extraOptions.put("cryptSharedLibPath", "<path to crypt_shared library>");
const extraOptions = {
cryptSharedLibPath: "<path to crypt_shared library>",
};
opts = AutoEncryptionOpts(
kms_providers,
key_vault.full_name,
bypass_query_analysis=True,
key_vault_client=client,
crypt_shared_lib_path="<path to FLE Shared Library>",
)

자세히 알아보기

이 경로에서 참조하는 라이브러리에 대해 자세히 알아보려면 Queryable Encryption을 위한 자동 암호화 공유 라이브러리 페이지를 참조하세요.

5

다음 자동 암호화 설정을 사용하여 MongoClient 객체를 인스턴스화합니다.

var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
var autoEncryptionOptions = new AutoEncryptionOptions(
keyVaultNamespace,
kmsProviders,
bypassQueryAnalysis: true,
extraOptions: extraOptions);
clientSettings.AutoEncryptionOptions = autoEncryptionOptions;
var secureClient = new MongoClient(clientSettings);
var collection = secureClient.GetDatabase(db).GetCollection<BsonDocument>(coll);
autoEncryptionOpts := options.AutoEncryption().
SetKmsProviders(kmsProviders).
SetKeyVaultNamespace(keyVaultNamespace).
SetExtraOptions(extraOptions).
SetBypassQueryAnalysis(true)
secureClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri).SetAutoEncryptionOptions(autoEncryptionOpts))
if err != nil {
return fmt.Errorf("Connect error for encrypted client: %v", err)
}
defer func() {
_ = secureClient.Disconnect(context.TODO())
}()
var coll = secureClient.Database(dbName).Collection(collName)
MongoClientSettings clientSettings = MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.autoEncryptionSettings(AutoEncryptionSettings.builder()
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.extraOptions(extraOptions)
.bypassQueryAnalysis(true)
.build())
.build();
MongoClient mongoClientSecure = MongoClients.create(clientSettings);
const encryptedClient = new MongoClient(uri, {
autoEncryption: {
kmsProviders: kmsProviders,
keyVaultNamespace: keyVaultNamespace,
bypassQueryAnalysis: true,
keyVaultClient: unencryptedClient,
extraOptions: extraOptions,
},
});
await encryptedClient.connect();
encrypted_client = MongoClient(connection_string, auto_encryption_opts=opts)
db = encrypted_client.medicalRecords
coll = db.patients

참고

자동 암호 해독

자동 암호 해독을 수행하기 위해 자동 암호화가 활성화된 MongoClient 인스턴스를 사용합니다.

자동 암호 해독을 사용한 명시적 암호화에 대해 자세히 알아보려면 기본 사항 섹션을 참조하세요.

6

다음과 같이 ClientEncryption 객체를 인스턴스화합니다.

var clientEncryptionOptions = new ClientEncryptionOptions(
keyVaultClient: regularClient,
keyVaultNamespace: keyVaultNamespace,
kmsProviders: kmsProviders
);
var clientEncryption = new ClientEncryption(clientEncryptionOptions);
clientEncryptionOpts := options.ClientEncryption().SetKeyVaultNamespace(keyVaultNamespace).SetKmsProviders(kmsProviders)
clientEnc, err := mongo.NewClientEncryption(regularClient, clientEncryptionOpts)
if err != nil {
panic(fmt.Errorf("NewClientEncryption error %v", err))
}
defer func() {
_ = clientEnc.Close(context.TODO())
}()
ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
.keyVaultMongoClientSettings(MongoClientSettings.builder()
.applyConnectionString(new ConnectionString(connectionString))
.build())
.keyVaultNamespace(keyVaultNamespace)
.kmsProviders(kmsProviders)
.build();
ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
const encryption = new ClientEncryption(unencryptedClient, {
keyVaultNamespace,
kmsProviders,
});
client_encryption = ClientEncryption(
kms_providers, key_vault_namespace, client, client.codec_options
)
5

Queryable Encryption이 활성화된 MongoClient 인스턴스를 사용하여 다음 코드 스니펫을 사용하여 암호화된 필드가 있는 문서를 medicalRecords.patients 네임스페이스에 삽입합니다.

var patientId = 12345678;
var medications = new BsonArray
{
new BsonString("Atorvastatin"),
new BsonString("Levothyroxine")
};
var indexedEncrypted = clientEncryption.Encrypt(
patientId,
new EncryptOptions(algorithm: "Indexed", keyId: dataKeyId1, contentionFactor: 1),
CancellationToken.None);
var unindexedEncrypted = clientEncryption.Encrypt(
medications,
new EncryptOptions(algorithm: "Unindexed", keyId: dataKeyId2),
CancellationToken.None);
collection.InsertOne(new BsonDocument { { "firstName", "Jon" }, { "patientId", indexedEncrypted }, { "medications", unindexedEncrypted } });
patientIdRawValueType, patientIdRawValueData, err := bson.MarshalValue(12345678)
if err != nil {
panic(err)
}
patientIdRawValue := bson.RawValue{Type: patientIdRawValueType, Value: patientIdRawValueData}
patientIdEncryptionOpts := options.Encrypt().
SetAlgorithm("Indexed").
SetKeyID(dataKeyID1).
SetContentionFactor(1)
patientIdEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
patientIdRawValue,
patientIdEncryptionOpts)
if err != nil {
panic(err)
}
medicationsRawValueType, medicationsRawValueData, err := bson.MarshalValue([]string{"Atorvastatin", "Levothyroxine"})
if err != nil {
panic(err)
}
medicationsRawValue := bson.RawValue{Type: medicationsRawValueType, Value: medicationsRawValueData}
medicationsEncryptionOpts := options.Encrypt().
SetAlgorithm("Unindexed").
SetKeyID(dataKeyID2)
medicationsEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
medicationsRawValue,
medicationsEncryptionOpts)
if err != nil {
panic(err)
}
_, err = coll.InsertOne(
context.TODO(),
bson.D{{"firstName", "Jon"}, {"patientId", patientIdEncryptedField}, {"medications", medicationsEncryptedField}})
if err != nil {
panic(err)
}
BsonInt32 patientId = new BsonInt32(12345678);
ArrayList<BsonString> medications = new ArrayList<>();
medications.add(new BsonString("Atorvastatin"));
medications.add(new BsonString("Levothyroxine"));
BsonBinary indexedEncrypted = clientEncryption.encrypt(patientId, new EncryptOptions("Indexed").keyId(dataKeyId1).contentionFactor(1L));
BsonBinary unindexedEncrypted = clientEncryption.encrypt(new BsonArray(medications), new EncryptOptions("Unindexed").keyId(dataKeyId2));
MongoCollection<BsonDocument> collection = mongoClientSecure.getDatabase(db).getCollection(coll, BsonDocument.class);
collection.insertOne(new BsonDocument("firstName", new BsonString("Jon")).append("patientId", indexedEncrypted).append("medications", unindexedEncrypted));
const patientId = 12345678;
const medications = ["Atorvastatin", "Levothyroxine"];
const indexedInsertPayload = await encryption.encrypt(patientId, {
algorithm: "Indexed",
keyId: dek1._id,
contentionFactor: 1,
});
const unindexedInsertPayload = await encryption.encrypt(medications, {
algorithm: "Unindexed",
keyId: dek2._id,
});
const encryptedColl = encryptedClient
.db(secretDB)
.collection(secretCollection);
await encryptedColl.insertOne({
firstName: "Jon",
patientId: indexedInsertPayload,
medications: unindexedInsertPayload,
});
patientId = 12345678
medications = ["Atorvastatin", "Levothyroxine"]
indexed_insert_payload = client_encryption.encrypt(
patientId, Algorithm.INDEXED, data_key_id_1, contention_factor=1
)
unindexed_insert_payload = client_encryption.encrypt(
medications, Algorithm.UNINDEXED, data_key_id_2
)
coll.insert_one(
{
"firstName": "Jon",
"patientId": indexed_insert_payload,
"medications": unindexed_insert_payload,
}
)

문서를 삽입하면 Queryable Encryption이 활성화된 클라이언트가 다음과 같이 문서의 필드를 암호화합니다.

{
"_id": {
"$oid": "6303e36053cc7ec2e6a630bd"
},
"firstName": "Jon",
"patientId": {
"$binary": {
"base64": "BxLJUBmg703civqMz8ASsD4QEYeSneOGiiYHfLE77ELEkp1EC/fXPrKCNRQl2mAFddszqDJ0P3znKrq0DVMEvJoU6wa0Ra+U+JjNVr8NtJE+TpTLCannY5Av6iGfLAaiHbM/E8Ftz1YCQsArQwuNp3wIV/GJPLa2662xsyk0wz7F6IRGC3FlnxpN4UIFaHE1M7Y6kEnx3tEy5uJBvU4Sex7I2H0kqHthClH77Q6xHIHc8H9d6upvgnEbkKBCnmc24A2pSG/xZ7LBsV3j5aOboPISuN/lvg==",
"subType": "06"
}
},
"medications": {
"$binary": {
"base64": "BvOsveapfUxiuQxCMSM2fYIEyRlQaSqR+0NxlMarwurBflvoMz1FrSjSGgCVCpK8X+YrilP6Bac99kkaUmRJfjo4savxcjpOfEnUj5bHciPyfQBYmYF4PMLDtTTzGZpPilb9d5KgpIMBXxHi+dIcog==",
"subType": "06"
}
},
"__safeContent__": [
{
"$binary": {
"base64": "ZLPIpgxzXpHUGrvdIHetwmMagR+mqvuUj5nzXNGf/WM=",
"subType": "00"
}
}
]
}

경고

__safeContent__ 필드를 수정하지 마세요.

__safeContent__ 필드는 Queryable Encryption에 반드시 필요합니다. 이 필드의 내용은 수정하지 마세요.

참조: 코드 완성

명시적 암호화로 암호화된 문서를 삽입하는 전체 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

명시적 암호화로 암호화된 문서를 삽입하는 전체 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

명시적 암호화로 암호화된 문서를 삽입하는 전체 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

명시적 암호화로 암호화된 문서를 삽입하는 전체 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

명시적 암호화로 암호화된 문서를 삽입하는 전체 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

6

암호화된 필드에 대한 쿼리를 통해 이 가이드의 암호화된 필드가 있는 문서 삽입 단계에서 삽입한 암호화된 필드가 있는 문서를 검색합니다.

var findPayload = clientEncryption.Encrypt(
patientId,
new EncryptOptions(algorithm: "Indexed", keyId: dataKeyId1, queryType: "equality", contentionFactor: 1),
CancellationToken.None);
var doc = collection.Find(new BsonDocument { { "patientId", findPayload } }).Single();
Console.WriteLine($"Encrypted document: {doc}");
findPayloadRawValueType, findPayloadRawValueData, err := bson.MarshalValue(12345678)
if err != nil {
panic(err)
}
findPayloadRawValue := bson.RawValue{Type: findPayloadRawValueType, Value: findPayloadRawValueData}
findPayloadEncryptionOpts := options.Encrypt().
SetAlgorithm("Indexed").
SetKeyID(dataKeyID1).
SetQueryType("equality").
SetContentionFactor(1)
findPayloadEncryptedField, err := clientEnc.Encrypt(
context.TODO(),
findPayloadRawValue,
findPayloadEncryptionOpts)
if err != nil {
panic(err)
}
var resultSecure bson.M
coll.FindOne(context.TODO(), bson.D{{"firstName", findPayloadEncryptedField}}).Decode(&resultSecure)
if err != nil {
panic(err)
}
outputSecure, err := json.MarshalIndent(resultSecure, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("\nFound document searching on explicitly encrypted field:\n%s\n", outputSecure)
BsonBinary findPayloadEncrypted = clientEncryption.encrypt(patientId, new EncryptOptions("Indexed").keyId(dataKeyId1).queryType("equality").contentionFactor(1L));
BsonDocument result = collection.find(eq("patientId", findPayloadEncrypted)).first();
System.out.println("Finding a document with manually encrypted field: " + result.toJson());
const findPayload = await encryption.encrypt(patientId, {
algorithm: "Indexed",
keyId: dek1._id,
queryType: "equality",
contentionFactor: 1,
});
console.log("Finding a document with manually encrypted field:");
console.log(await encryptedColl.findOne({ patientId: findPayload }));
find_payload = client_encryption.encrypt(
patientId,
Algorithm.INDEXED,
data_key_id_1,
query_type=QueryType.EQUALITY,
contention_factor=1,
)
doc = coll.find_one({"encryptedIndexed": find_payload})
print("\nReturned document:\n")
pprint.pprint(doc)

앞의 코드 스니펫의 출력에는 다음 문서가 포함되어야 합니다.

{
"__safeContent__": [
{
"Subtype": 0,
"Data": "LfaIuWm9o30MIGrK7GGUoStJMSNOjRgbxy5q2TPiDes="
}
],
"_id": "6303a770857952ca5e363fd2",
"firstName": "Jon",
"medications": ["Atorvastatin", "Levothyroxine"],
"patientId": 12345678
}

참조: 코드 완성

암호화된 필드가 있는 문서를 검색하는 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

암호화된 필드가 있는 문서를 검색하는 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

암호화된 필드가 있는 문서를 검색하는 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

암호화된 필드가 있는 문서를 검색하는 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

암호화된 필드가 있는 문서를 검색하는 코드를 보려면 Queryable Encryption 샘플 애플리케이션 리포지토리를 참조하세요.

원격 KMS에서 Queryable Encryption을 사용하는 방법에 대한 튜토리얼을 보려면 튜토리얼을 참조하세요 .

Queryable Encryption의 작동 방식을 알아보려면 명시적 암호화를 참조하세요.

이 가이드에 언급된 주제에 대해 자세히 알아보려면 다음 링크를 참조하세요:

돌아가기

KMIP로 자동 Queryable Encryption 사용

다음

참조