Docs Menu
Docs Home
/
MongoDB ๋งค๋‰ด์–ผ
/ / / /

๋น ๋ฅธ ์‹œ์ž‘

์ด ํŽ˜์ด์ง€์˜ ๋‚ด์šฉ

  • ๊ฐœ์š”
  • ์‹œ์ž‘ํ•˜๊ธฐ ์ „์—
  • ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ
  • ์ ˆ์ฐจ
  • ๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค ์ƒ์„ฑ
  • ํ‚ค ๋ณผํŠธ collection์— ๊ณ ์œ  ์ธ๋ฑ์Šค ๋งŒ๋“ค๊ธฐ
  • ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค ์ƒ์„ฑ
  • MongoClient ๊ตฌ์„ฑ
  • ์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ ์‚ฝ์ž…ํ•˜๊ธฐ
  • ์•”ํ˜ธํ™”๋œ ํ•„๋“œ๋กœ ๋ฌธ์„œ ๊ฒ€์ƒ‰ํ•˜๊ธฐ
  • ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ธฐ

์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ์ž๋™ CSFLE(ํด๋ผ์ด์–ธํŠธ ์ธก ํ•„๋“œ ๋ ˆ๋ฒจ ์•”ํ˜ธํ™”) ๋ฐ MongoDB ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์„œ๋ฅผ ์•”ํ˜ธํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์ด ๊ฐ€์ด๋“œ๋ฅผ ์™„๋ฃŒํ•œ ํ›„์—๋Š” ๋‹ค์Œ ์ง€์‹๊ณผ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • ๋ฌธ์„œ์˜ ํ•„๋“œ๋ฅผ ์•”ํ˜ธํ™”ํ•˜๋„๋ก ๋“œ๋ผ์ด๋ฒ„๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋‹จ๊ณ„๋ฅผ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.

  • ์ž‘๋™ํ•˜์ง€๋งŒ ํ”„๋กœ๋•์…˜ ์ค€๋น„๊ฐ€ ๋˜์ง€ ์•Š์€ ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ์ž๋™ ํด๋ผ์ด์–ธํŠธ ์ธก ํ•„๋“œ ๋ ˆ๋ฒจ ์•”ํ˜ธํ™”๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ค‘์š”

์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.

์ด ์˜ˆ์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ์ €์žฅํ•˜๋ฏ€๋กœ ํ‚ค์— ๋ฌด๋‹จ์œผ๋กœ ์•ก์„ธ์Šคํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•ด๋…ํ•˜๊ธฐ ์œ„ํ•œ ํ‚ค๋ฅผ ๋ถ„์‹คํ•  ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ๋•์…˜์šฉ CSFLE ์ง€์› ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ํŠœํ† ๋ฆฌ์–ผ์„ ๋ณด๋ ค๋ฉด ํŠœํ† ๋ฆฌ์–ผ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

์ด ๊ฐ€์ด๋“œ์˜ ์ฝ”๋“œ๋ฅผ ์™„๋ฃŒํ•˜๊ณ  ์‹คํ–‰ํ•˜๋ ค๋ฉด ์„ค์น˜ ์š”๊ตฌ ์‚ฌํ•ญ ํŽ˜์ด์ง€์— ํ‘œ์‹œ๋œ ๋Œ€๋กœ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€ ์˜ค๋ฅธ์ชฝ์˜ Select your language ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด์—์„œ ์ฝ”๋“œ ์˜ˆ์‹œ๋ฅผ ๋ณด๋ ค๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

์ƒ˜ํ”Œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด ์–ธ์–ด ์„ ํƒ๊ธฐ์—์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ๋ฅผ ์„ ํƒํ•˜์„ธ์š”.

C# ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์™„์„ฑ

// You are viewing the C# driver code examples.
// Use the dropdown menu to select a different driver.
// You are viewing the Golang driver code examples.
// Use the dropdown menu to select a different driver.

์ค‘์š”

go build ๋˜๋Š” go run๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๊ฐ€์ด๋“œ ์˜ Go ์ฝ”๋“œ๋ฅผ ๋นŒ๋“œํ•˜๊ฑฐ๋‚˜ ์‹คํ–‰ ๋•Œ๋Š” ํ•ญ์ƒ cse ๋นŒ๋“œ ์ œ์•ฝ ์กฐ๊ฑด์„ ํฌํ•จํ•˜์—ฌ CSFLE ๋ฅผ ํ™œ์„ฑํ™” ํ•˜์„ธ์š”. ๋นŒ๋“œ ์ œ์•ฝ ์กฐ๊ฑด์„ ํฌํ•จํ•˜๋Š” ์˜ˆ์‹œ ๋Š” ๋‹ค์Œ shell ๋ช…๋ น์„ ์ฐธ์กฐํ•˜์„ธ์š”.

go run -tags cse insert-encrypted-document.go
// You are viewing the Java synchronous driver code examples.
// Use the dropdown menu to select a different driver.
// You are viewing the Node.js driver code examples.
// Use the dropdown menu to select a different driver.
# You are viewing the Python driver code examples.
# Use the dropdown menu to select a different driver.
1

CSFLE๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค(CMK)๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

96๋ฐ”์ดํŠธ ๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํŒŒ์ผ ์‹œ์Šคํ…œ์ธ ๋กœ์ปฌ ํ‚ค ์ œ๊ณต์ž ์— master-key.txt ํŒŒ์ผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

const fs = require("fs");
const crypto = require("crypto");
try {
fs.writeFileSync("master-key.txt", crypto.randomBytes(96));
} catch (err) {
console.error(err);
}
using (var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create())
{
var bytes = new byte[96];
randomNumberGenerator.GetBytes(bytes);
var localMasterKeyBase64Write = Convert.ToBase64String(bytes);
Console.WriteLine(localMasterKeyBase64Write);
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);
}
import os
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/macOS ์…ธ:

    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 ํŒŒ์ผ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

ํŒ

์ฐธ์กฐ: ์ฝ”๋“œ ์™„์„ฑ

๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

2

encryption.__keyVault ๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ keyAltNames ํ•„๋“œ์— ๋ถ€๋ถ„ ๊ณ ์œ  ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ์ธ๋ฑ์Šค๋Š” keyAltNames ๊ฐ€ ์กด์žฌํ•˜๋Š” ๋ฌธ์„œ์— ๋Œ€ํ•ด partialFilterExpression ์„ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ ์ธก ํ•„๋“œ ๋ ˆ๋ฒจ ์•”ํ˜ธํ™”๋Š” ์„œ๋ฒ„์—์„œ ์ ์šฉ๋˜๋Š” ํ‚ค ๋Œ€์ฒด ์ด๋ฆ„์˜ ๊ณ ์œ ์„ฑ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

์„ ํ˜ธํ•˜๋Š” MongoDB ๋“œ๋ผ์ด๋ฒ„์— ํ•ด๋‹นํ•˜๋Š” ํƒญ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค:

var connectionString = "<Your MongoDB URI>";
var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
var keyVaultClient = new MongoClient(connectionString);
var indexOptions = new CreateIndexOptions<BsonDocument>();
indexOptions.Unique = true;
indexOptions.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.ToString());
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
keyVaultDatabase.DropCollection(keyVaultNamespace.CollectionName);
// Drop the database storing your encrypted fields as all
// the DEKs encrypting those fields were deleted in the preceding line.
keyVaultClient.GetDatabase("medicalRecords").DropCollection("patients");
var keyVaultCollection = keyVaultDatabase.GetCollection<BsonDocument>(keyVaultNamespace.CollectionName.ToString());
keyVaultCollection.Indexes.CreateOne(indexModel);
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())
}()
keyVaultColl := "__keyVault"
keyVaultDb := "encryption"
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)
}
// Drop the database storing your encrypted fields as all
// the DEKs encrypting those fields were deleted in the preceding line.
if err = keyVaultClient.Database("medicalRecords").Collection("patients").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 connectionString = "<Your MongoDB URI>";
String keyVaultDb = "encryption";
String keyVaultColl = "__keyVault";
String keyVaultNamespace = keyVaultDb + "." + keyVaultColl;
MongoClient keyVaultClient = MongoClients.create(connectionString);
// Drop the Key Vault Collection in case you created this collection
// in a previous run of this application.
keyVaultClient.getDatabase(keyVaultDb).getCollection(keyVaultColl).drop();
// Drop the database storing your encrypted fields as all
// the DEKs encrypting those fields were deleted in the preceding line.
keyVaultClient.getDatabase("medicalRecords").getCollection("patients").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 keyVaultDatabase = "encryption";
const keyVaultCollection = "__keyVault";
const keyVaultNamespace = `${keyVaultDatabase}.${keyVaultCollection}`;
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();
// Drop the database storing your encrypted fields as all
// the DEKs encrypting those fields were deleted in the preceding line.
await keyVaultClient.db("medicalRecords").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)
# Drop the database storing your encrypted fields as all
# the DEKs encrypting those fields were deleted in the preceding line.
key_vault_client["medicalRecords"].drop_collection("patients")
key_vault_client[key_vault_db][key_vault_coll].create_index(
[("keyAltNames", ASCENDING)],
unique=True,
partialFilterExpression={"keyAltNames": {"$exists": True}},
)
3
  1. ๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค ์ฝ๊ธฐ ๋ฐ KMS ์ œ๊ณต์ž ์„ค์ • ์ง€์ •

    ์ด ๊ฐ€์ด๋“œ์˜ ๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค ์ƒ์„ฑ ๋‹จ๊ณ„์—์„œ ์ƒ์„ฑํ•œ ๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.

    KMS ์ œ๊ณต์ž ์„ค์ •์—์„œ CMK ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ๋Š” ์ด๋Ÿฌํ•œ ์„ค์ •์„ ์‚ฌ์šฉํ•˜์—ฌ CMK ๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค. ๋กœ์ปฌ ํ‚ค ์ œ๊ณต์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ œ๊ณต์ž ์ด๋ฆ„์„ local ๋กœ ์„ค์ •ํ•˜๋‹ค ํ•ฉ๋‹ˆ๋‹ค.

    var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>();
    var provider = "local";
    string localMasterKeyBase64Read = File.ReadAllText("master-key.txt");
    var localMasterKeyBytes = Convert.FromBase64String(localMasterKeyBase64Read);
    var localOptions = new Dictionary<string, object>
    {
    { "key", localMasterKeyBytes }
    };
    kmsProviders.Add("local", 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";
    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
    },
    }
  2. ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค ์ƒ์„ฑ

    MongoDB ์—ฐ๊ฒฐ ๋ฌธ์ž์—ด๊ณผ ํ‚ค ๋ณผํŠธ ์ปฌ๋ ‰์…˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

    ์ฐธ๊ณ 

    ํ‚ค ๋ณผํŠธ ์ปฌ๋ ‰์…˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ถŒํ•œ

    ์ด ํŠœํ† ๋ฆฌ์–ผ์„ ์™„๋ฃŒํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ MongoDB์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์šฉ์ž์—๊ฒŒ ๋‹ค์Œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ๋Œ€ํ•œ dbAdmin ๊ถŒํ•œ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    • encryption.__keyVault

    • medicalRecords database

    var clientEncryptionOptions = new ClientEncryptionOptions(
    keyVaultClient: keyVaultClient,
    keyVaultNamespace: keyVaultNamespace,
    kmsProviders: kmsProviders
    );
    var clientEncryption = new ClientEncryption(clientEncryptionOptions);
    var dataKeyOptions = new DataKeyOptions();
    var dataKeyId = clientEncryption.CreateDataKey(provider, dataKeyOptions, CancellationToken.None);
    var dataKeyIdBase64 = Convert.ToBase64String(GuidConverter.ToBytes(dataKeyId, GuidRepresentation.Standard));
    Console.WriteLine($"DataKeyId [base64]: {dataKeyIdBase64}");
    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())
    }()
    dataKeyOpts := options.DataKey()
    dataKeyID, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts)
    if err != nil {
    return fmt.Errorf("create data key error %v", err)
    }
    fmt.Printf("DataKeyId [base64]: %s\n", base64.StdEncoding.EncodeToString(dataKeyID.Data))
    ClientEncryptionSettings clientEncryptionSettings = ClientEncryptionSettings.builder()
    .keyVaultMongoClientSettings(MongoClientSettings.builder()
    .applyConnectionString(new ConnectionString(connectionString))
    .build())
    .keyVaultNamespace(keyVaultNamespace)
    .kmsProviders(kmsProviders)
    .build();
    MongoClient regularClient = MongoClients.create(connectionString);
    ClientEncryption clientEncryption = ClientEncryptions.create(clientEncryptionSettings);
    BsonBinary dataKeyId = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions());
    String base64DataKeyId = Base64.getEncoder().encodeToString(dataKeyId.getData());
    System.out.println("DataKeyId [base64]: " + base64DataKeyId);
    clientEncryption.close();
    const client = new MongoClient(uri);
    await client.connect();
    const encryption = new ClientEncryption(client, {
    keyVaultNamespace,
    kmsProviders,
    });
    const key = await encryption.createDataKey(provider);
    console.log("DataKeyId [base64]: ", key.toString("base64"));
    await keyVaultClient.close();
    await client.close();

    ์ฐธ๊ณ 

    ํด๋ผ์ด์–ธํŠธ ์•”ํ˜ธํ™” ๊ฐ€์ ธ์˜ค๊ธฐ

    Node.js ๋“œ๋ผ์ด๋ฒ„ v6.0 ์ด์ƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ mongodb์—์„œ ClientEncryption์„(๋ฅผ) ๊ฐ€์ ธ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์ด์ „ ๋“œ๋ผ์ด๋ฒ„ ๋ฒ„์ „์˜ ๊ฒฝ์šฐ mongodb-client-encryption์—์„œ ClientEncryption์„(๋ฅผ) ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

    key_vault_database = "encryption"
    key_vault_collection = "__keyVault"
    key_vault_namespace = f"{key_vault_database}.{key_vault_collection}"
    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 = client_encryption.create_data_key("local")
    base_64_data_key_id = base64.b64encode(data_key_id)
    print("DataKeyId [base64]: ", base_64_data_key_id)

    ์œ„ ์ฝ”๋“œ์˜ ์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    DataKeyId [base64]: 3k13WkSZSLy7kwAAP4HDyQ==

ํŒ

์ฐธ์กฐ: ์ฝ”๋“œ ์™„์„ฑ

๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

4
  1. ํ‚ค ๋ณผํŠธ collection ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ง€์ •ํ•˜๊ธฐ

    ํ‚ค ๋ณผํŠธ collection ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ encryption.__keyVault ์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

    var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
    keyVaultNamespace := "encryption.__keyVault"
    String keyVaultNamespace = "encryption.__keyVault";
    const keyVaultNamespace = "encryption.__keyVault";
    key_vault_namespace = "encryption.__keyVault"
  2. ๋กœ์ปฌ ๊ณ ๊ฐ ๋งˆ์Šคํ„ฐ ํ‚ค ์ง€์ •

    KMS ์ œ๊ณต์ž๋ฅผ ์ง€์ •ํ•˜๊ณ  ํ‚ค๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

    var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>();
    var provider = "local";
    var localMasterKeyPath = "master-key.txt";
    string 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<String, Object>();
    keyMap.put("key", localMasterKeyRead);
    Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>();
    kmsProviders.put("local", keyMap);
    const fs = require("fs");
    const provider = "local";
    const path = "./master-key.txt";
    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. ์ปฌ๋ ‰์…˜์— ๋Œ€ํ•œ ์•”ํ˜ธํ™” ์Šคํ‚ค๋งˆ ๋งŒ๋“ค๊ธฐ

    ํŒ

    ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค Base64 ID ์ถ”๊ฐ€ํ•˜๊ธฐ

    ๊ธฐ๋ณธ64 DEK ID๋ฅผ ํฌํ•จํ•˜๋„๋ก ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ€์ด๋“œ์˜ ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ‚ค ์ƒ์„ฑ ๋‹จ๊ณ„์—์„œ ์ด ๊ฐ’์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

    var keyId = "<Your base64 DEK ID here>";
    var schema = new BsonDocument
    {
    { "bsonType", "object" },
    {
    "encryptMetadata",
    new BsonDocument("keyId", new BsonArray(new[] { new BsonBinaryData(Convert.FromBase64String(keyId), BsonBinarySubType.UuidStandard) }))
    },
    {
    "properties",
    new BsonDocument
    {
    {
    "ssn", new BsonDocument
    {
    {
    "encrypt", new BsonDocument
    {
    { "bsonType", "int" },
    { "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" }
    }
    }
    }
    },
    {
    "bloodType", new BsonDocument
    {
    {
    "encrypt", new BsonDocument
    {
    { "bsonType", "string" },
    { "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random" }
    }
    }
    }
    },
    {
    "medicalRecords", new BsonDocument
    {
    {
    "encrypt", new BsonDocument
    {
    { "bsonType", "array" },
    { "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random" }
    }
    }
    }
    },
    {
    "insurance", new BsonDocument
    {
    { "bsonType", "object" },
    {
    "properties", new BsonDocument
    {
    {
    "policyNumber", new BsonDocument
    {
    {
    "encrypt", new BsonDocument
    {
    { "bsonType", "int" },
    { "algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    };
    var schemaMap = new Dictionary<string, BsonDocument>();
    schemaMap.Add(dbNamespace, schema);
    dek_id := "<Your Base64 DEK ID>"
    schema_template := `{
    "bsonType": "object",
    "encryptMetadata": {
    "keyId": [
    {
    "$binary": {
    "base64": "%s",
    "subType": "04"
    }
    }
    ]
    },
    "properties": {
    "insurance": {
    "bsonType": "object",
    "properties": {
    "policyNumber": {
    "encrypt": {
    "bsonType": "int",
    "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
    }
    }
    }
    },
    "medicalRecords": {
    "encrypt": {
    "bsonType": "array",
    "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
    }
    },
    "bloodType": {
    "encrypt": {
    "bsonType": "string",
    "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
    }
    },
    "ssn": {
    "encrypt": {
    "bsonType": "int",
    "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
    }
    }
    }
    }`
    schema := fmt.Sprintf(schema_template, dek_id)
    var schemaDoc bson.Raw
    if err := bson.UnmarshalExtJSON([]byte(schema), true, &schemaDoc); err != nil {
    return fmt.Errorf("UnmarshalExtJSON error: %v", err)
    }
    schemaMap := map[string]interface{}{
    dbName + "." + collName: schemaDoc,
    }
    String dekId = "<paste-base-64-encoded-data-encryption-key-id>>";
    Document jsonSchema = new Document().append("bsonType", "object").append("encryptMetadata",
    new Document().append("keyId", new ArrayList<>((Arrays.asList(new Document().append("$binary", new Document()
    .append("base64", dekId)
    .append("subType", "04")))))))
    .append("properties", new Document()
    .append("ssn", new Document().append("encrypt", new Document()
    .append("bsonType", "int")
    .append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")))
    .append("bloodType", new Document().append("encrypt", new Document()
    .append("bsonType", "string")
    .append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random")))
    .append("medicalRecords", new Document().append("encrypt", new Document()
    .append("bsonType", "array")
    .append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Random")))
    .append("insurance", new Document()
    .append("bsonType", "object")
    .append("properties",
    new Document().append("policyNumber", new Document().append("encrypt", new Document()
    .append("bsonType", "int")
    .append("algorithm", "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"))))));
    HashMap<String, BsonDocument> schemaMap = new HashMap<String, BsonDocument>();
    schemaMap.put("medicalRecords.patients", BsonDocument.parse(jsonSchema.toJson()));
    dataKey = "<Your base64 DEK ID>";
    const schema = {
    bsonType: "object",
    encryptMetadata: {
    keyId: [new Binary(Buffer.from(dataKey, "base64"), 4)],
    },
    properties: {
    insurance: {
    bsonType: "object",
    properties: {
    policyNumber: {
    encrypt: {
    bsonType: "int",
    algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
    },
    },
    },
    },
    medicalRecords: {
    encrypt: {
    bsonType: "array",
    algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
    },
    },
    bloodType: {
    encrypt: {
    bsonType: "string",
    algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
    },
    },
    ssn: {
    encrypt: {
    bsonType: "int",
    algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
    },
    },
    },
    };
    var patientSchema = {};
    patientSchema[namespace] = schema;
    dek_id = b"<paste-base-64-encoded-data-encryption-key-id>"
    json_schema = {
    "bsonType": "object",
    "encryptMetadata": {"keyId": [Binary(base64.b64decode(dek_id), UUID_SUBTYPE)]},
    "properties": {
    "insurance": {
    "bsonType": "object",
    "properties": {
    "policyNumber": {
    "encrypt": {
    "bsonType": "int",
    "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
    }
    }
    },
    },
    "medicalRecords": {
    "encrypt": {
    "bsonType": "array",
    "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
    }
    },
    "bloodType": {
    "encrypt": {
    "bsonType": "string",
    "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
    }
    },
    "ssn": {
    "encrypt": {
    "bsonType": "int",
    "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
    }
    },
    },
    }
    patient_schema = {"medicalRecords.patients": json_schema}
  4. ์ž๋™ ์•”ํ˜ธํ™” ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์œ„์น˜ ์ง€์ •

    var mongoBinariesPath = "<Full path to your Automatic Encryption Shared Library>";
    var extraOptions = new Dictionary<string, object>()
    {
    { "cryptSharedLibPath", mongoBinariesPath },
    };
    extraOptions := map[string]interface{}{
    "cryptSharedLibPath": "<Full path to your Automatic Encryption Shared Library>",
    }
    Map<String, Object> extraOptions = new HashMap<String, Object>();
    extraOptions.put("cryptSharedLibPath", "<Full path to your Automatic Encryption Shared Library>"));
    const extraOptions = {
    cryptSharedLibPath: "<Full path to your Automatic Encryption Shared Library>",
    };
    extra_options = {
    "cryptSharedLibPath": "<Full path to your Automatic Encryption Shared Library>"
    }

    ์ฐธ๊ณ 

    ์ž๋™ ์•”ํ˜ธํ™” ์˜ต์…˜

    ์ž๋™ ์•”ํ˜ธํ™” ์˜ต์…˜์€ ์ž๋™ ์•”ํ˜ธํ™” ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๊ตฌ์„ฑ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์—ฌ ์•”ํ˜ธํ™”๋œ ํ•„๋“œ์— ์•ก์„ธ์Šคํ•  ๋•Œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋™์ž‘์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

    ์ž๋™ ์•”ํ˜ธํ™” ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํ•™์Šต ๋ณด๋ ค๋ฉด CSFLE ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ ๋ฐ ๊ตฌ์„ฑ ํŽ˜์ด์ง€๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

  5. MongoClient ์ƒ์„ฑ

    ๋‹ค์Œ ์ž๋™ ์•”ํ˜ธํ™” ์„ค์ •์„ ์‚ฌ์šฉํ•˜์—ฌ MongoDB ํด๋ผ์ด์–ธํŠธ ๊ฐ์ฒด๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•ฉ๋‹ˆ๋‹ค.

    MongoClientSettings.Extensions.AddAutoEncryption(); // .NET/C# Driver v3.0 or later only
    var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
    var autoEncryptionOptions = new AutoEncryptionOptions(
    keyVaultNamespace: keyVaultNamespace,
    kmsProviders: kmsProviders,
    schemaMap: schemaMap,
    extraOptions: extraOptions
    );
    clientSettings.AutoEncryptionOptions = autoEncryptionOptions;
    var secureClient = new MongoClient(clientSettings);
    var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
    var autoEncryptionOptions = new AutoEncryptionOptions(
    keyVaultNamespace: keyVaultNamespace,
    kmsProviders: kmsProviders,
    schemaMap: schemaMap,
    extraOptions: extraOptions
    );
    clientSettings.AutoEncryptionOptions = autoEncryptionOptions;
    var secureClient = new MongoClient(clientSettings);
    autoEncryptionOpts := options.AutoEncryption().
    SetKmsProviders(kmsProviders).
    SetKeyVaultNamespace(keyVaultNamespace).
    SetSchemaMap(schemaMap).
    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())
    }()
    MongoClientSettings clientSettings = MongoClientSettings.builder()
    .applyConnectionString(new ConnectionString(connectionString))
    .autoEncryptionSettings(AutoEncryptionSettings.builder()
    .keyVaultNamespace(keyVaultNamespace)
    .kmsProviders(kmsProviders)
    .schemaMap(schemaMap)
    .extraOptions(extraOptions)
    .build())
    .build();
    MongoClient mongoClientSecure = MongoClients.create(clientSettings);
    const secureClient = new MongoClient(connectionString, {
    autoEncryption: {
    keyVaultNamespace,
    kmsProviders,
    schemaMap: patientSchema,
    extraOptions: extraOptions,
    },
    });
    fle_opts = AutoEncryptionOpts(
    kms_providers, key_vault_namespace, schema_map=patient_schema, **extra_options
    )
    secureClient = MongoClient(connection_string, auto_encryption_opts=fle_opts)
5

CSFLE ์ง€์› MongoClient ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์‚ฌ์šฉํ•˜์—ฌ ์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ medicalRecords.patients ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.

var sampleDocFields = new BsonDocument
{
{ "name", "Jon Doe" },
{ "ssn", 145014000 },
{ "bloodType", "AB-" },
{
"medicalRecords", new BsonArray
{
new BsonDocument("weight", 180),
new BsonDocument("bloodPressure", "120/80")
}
},
{
"insurance", new BsonDocument
{
{ "policyNumber", 123142 },
{ "provider", "MaestCare" }
}
}
};
// Construct an auto-encrypting client
var secureCollection = secureClient.GetDatabase(db).GetCollection<BsonDocument>(coll);
// Insert a document into the collection
secureCollection.InsertOne(sampleDocFields);
test_patient := map[string]interface{}{
"name": "Jon Doe",
"ssn": 241014209,
"bloodType": "AB+",
"medicalRecords": []map[string]interface{}{{
"weight": 180,
"bloodPressure": "120/80",
}},
"insurance": map[string]interface{}{
"provider": "MaestCare",
"policyNumber": 123142,
},
}
if _, err := secureClient.Database(dbName).Collection(collName).InsertOne(context.TODO(), test_patient); err != nil {
return fmt.Errorf("InsertOne error: %v", err)
}

์ฐธ๊ณ 

์›์‹œ BSON ๋ฌธ์„œ๋ฅผ ๋งŒ๋“œ๋Š” ๋Œ€์‹  bson ํƒœ๊ทธ๊ฐ€ ์žˆ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ๋“œ๋ผ์ด๋ฒ„์— ์ง์ ‘ ์ „๋‹ฌํ•˜์—ฌ ์ธ์ฝ”๋”ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ArrayList<Document> medicalRecords = new ArrayList<>();
medicalRecords.add(new Document().append("weight", "180"));
medicalRecords.add(new Document().append("bloodPressure", "120/80"));
Document insurance = new Document()
.append("policyNumber", 123142)
.append("provider", "MaestCare");
Document patient = new Document()
.append("name", "Jon Doe")
.append("ssn", 241014209)
.append("bloodType", "AB+")
.append("medicalRecords", medicalRecords)
.append("insurance", insurance);
mongoClientSecure.getDatabase(recordsDb).getCollection(recordsColl).insertOne(patient);
try {
const writeResult = await secureClient
.db(db)
.collection(coll)
.insertOne({
name: "Jon Doe",
ssn: 241014209,
bloodType: "AB+",
medicalRecords: [{ weight: 180, bloodPressure: "120/80" }],
insurance: {
policyNumber: 123142,
provider: "MaestCare",
},
});
} catch (writeError) {
console.error("writeError occurred:", writeError);
}
def insert_patient(
collection, name, ssn, blood_type, medical_records, policy_number, provider
):
insurance = {"policyNumber": policy_number, "provider": provider}
doc = {
"name": name,
"ssn": ssn,
"bloodType": blood_type,
"medicalRecords": medical_records,
"insurance": insurance,
}
collection.insert_one(doc)
medical_record = [{"weight": 180, "bloodPressure": "120/80"}]
insert_patient(
secureClient.medicalRecords.patients,
"Jon Doe",
241014209,
"AB+",
medical_record,
123142,
"MaestCare",
)

๋ฌธ์„œ๋ฅผ ์‚ฝ์ž…ํ•˜๋ฉด CSFLE ํ™œ์„ฑํ™” ํด๋ผ์ด์–ธํŠธ๋Š” ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•˜๋„๋ก ๋ฌธ์„œ์˜ ํ•„๋“œ๋ฅผ ์•”ํ˜ธํ™”ํ•ฉ๋‹ˆ๋‹ค.

{
"_id": { "$oid": "<_id of your document>" },
"name": "Jon Doe",
"ssn": {
"$binary": "<cipher-text>",
"$type": "6"
},
"bloodType": {
"$binary": "<cipher-text>",
"$type": "6"
},
"medicalRecords": {
"$binary": "<cipher-text>",
"$type": "6"
},
"insurance": {
"provider": "MaestCare",
"policyNumber": {
"$binary": "<cipher-text>",
"$type": "6"
}
}
}

ํŒ

์ฐธ์กฐ: ์ฝ”๋“œ ์™„์„ฑ

์•”ํ˜ธํ™”๋จ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ ๋ฅผ ์‚ฝ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

6

์ด ๊ฐ€์ด๋“œ์˜ ์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ ์‚ฝ์ž… ๋‹จ๊ณ„์—์„œ ์‚ฝ์ž…ํ•œ ์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์€ ์ž๋™ CSFLE๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์„ฑ๋œ ํด๋ผ์ด์–ธํŠธ์™€ ์ž๋™ CSFLE๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ตฌ์„ฑ๋˜์ง€ ์•Š์€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์„œ์— ๋Œ€ํ•ด ์ฟผ๋ฆฌํ•จ์œผ๋กœ์จ CSFLE์˜ ๊ธฐ๋Šฅ์„ ๋ณด์—ฌ ์ค๋‹ˆ๋‹ค.

Console.WriteLine("Finding a document with regular (non-encrypted) client.");
var filter = Builders<BsonDocument>.Filter.Eq("name", "Jon Doe");
var regularResult = regularCollection.Find(filter).Limit(1).ToList()[0];
Console.WriteLine($"\n{regularResult}\n");
Console.WriteLine("Finding a document with encrypted client");
var ssnFilter = Builders<BsonDocument>.Filter.Eq("name", "Jon Doe");
var secureResult = secureCollection.Find(ssnFilter).Limit(1).First();
Console.WriteLine($"\n{secureResult}\n");
fmt.Println("Finding a document with regular (non-encrypted) client.")
var resultRegular bson.M
err = regularClient.Database(dbName).Collection(collName).FindOne(context.TODO(), bson.D{{"name", "Jon Doe"}}).Decode(&resultRegular)
if err != nil {
panic(err)
}
outputRegular, err := json.MarshalIndent(resultRegular, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("%s\n", outputRegular)
fmt.Println("Finding a document with encrypted client")
var resultSecure bson.M
err = secureClient.Database(dbName).Collection(collName).FindOne(context.TODO(), bson.D{{"name", "Jon Doe"}}).Decode(&resultSecure)
if err != nil {
panic(err)
}
outputSecure, err := json.MarshalIndent(resultSecure, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("%s\n", outputSecure)
System.out.println("Finding a document with regular (non-encrypted) client.");
Document docRegular = mongoClientRegular.getDatabase(recordsDb).getCollection(recordsColl).find(eq("name", "Jon Doe")).first();
System.out.println(docRegular.toJson());
System.out.println("Finding a document with encrypted client");
Document docSecure = mongoClientSecure.getDatabase(recordsDb).getCollection(recordsColl).find(eq("name", "Jon Doe")).first();
System.out.println(docSecure.toJson());
console.log("Finding a document with regular (non-encrypted) client.");
console.log(
await regularClient.db(db).collection(coll).findOne({ name: /Jon/ })
);
console.log("Finding a document with encrypted client");
console.log(
await secureClient.db(db).collection(coll).findOne({ name: /Jon/ })
);
print("Finding a document with regular (non-encrypted) client.")
result = regularClient.medicalRecords.patients.find_one({"name": "Jon Doe"})
pprint.pprint(result)
print("Finding a document with encrypted client")
pprint.pprint(secureClient.medicalRecords.patients.find_one({"name": "Jon Doe"}))

์ด์ „ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์˜ ์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Finding a document with regular (non-encrypted) client.
{
_id: new ObjectId("629a452e0861b3130887103a"),
name: 'Jon Doe',
ssn: new Binary(Buffer.from("0217482732d8014cdd9ffdd6e2966e5e7910c20697e5f4fa95710aafc9153f0a3dc769c8a132a604b468732ff1f4d8349ded3244b59cbfb41444a210f28b21ea1b6c737508d9d30e8baa30c1d8070c4d5e26", "hex"), 6),
bloodType: new Binary(Buffer.from("0217482732d8014cdd9ffdd6e2966e5e79022e238536dfd8caadb4d7751ac940e0f195addd7e5c67b61022d02faa90283ab69e02303c7e4001d1996128428bf037dea8bbf59fbb20c583cbcff2bf3e2519b4", "hex"), 6),
'key-id': 'demo-data-key',
medicalRecords: new Binary(Buffer.from("0217482732d8014cdd9ffdd6e2966e5e790405163a3207cff175455106f57eef14e5610c49a99bcbd14a7db9c5284e45e3ee30c149354015f941440bf54725d6492fb3b8704bc7c411cff6c868e4e13c58233c3d5ed9593eca4e4d027d76d3705b6d1f3b3c9e2ceee195fd944b553eb27eee69e5e67c338f146f8445995664980bf0", "hex"), 6),
insurance: {
policyNumber: new Binary(Buffer.from("0217482732d8014cdd9ffdd6e2966e5e79108decd85c05be3fec099e015f9d26d9234605dc959cc1a19b63072f7ffda99db38c7b487de0572a03b2139ac3ee163bcc40c8508f366ce92a5dd36e38b3c742f7", "hex"), 6),
provider: 'MaestCare'
}
}
Finding a document with encrypted client
{
_id: new ObjectId("629a452e0861b3130887103a"),
name: 'Jon Doe',
ssn: 241014209,
bloodType: 'AB+',
'key-id': 'demo-data-key',
medicalRecords: [ { weight: 180, bloodPressure: '120/80' } ],
insurance: { policyNumber: 123142, provider: 'MaestCare' }
}

ํŒ

์ฐธ์กฐ: ์ฝ”๋“œ ์™„์„ฑ

์•”ํ˜ธํ™”๋จ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์•”ํ˜ธํ™”๋œ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๋ฌธ์„œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ๋ณด๋ ค๋ฉด Github ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์›๊ฒฉ KMS๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ๋•์…˜์— ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ CSFLE์— ๋Œ€ํ•œ ํŠœํ† ๋ฆฌ์–ผ์„ ๋ณด๋ ค๋ฉด ํŠœํ† ๋ฆฌ์–ผ์„ ์ฐธ์กฐํ•˜์„ธ์š” .

CSFLE ์ž‘๋™ ๋ฐฉ์‹์„ ์•Œ์•„๋ณด๋ ค๋ฉด ๊ธฐ๋ณธ ์‚ฌํ•ญ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

์ด ๊ฐ€์ด๋“œ์— ์–ธ๊ธ‰๋œ ์ฃผ์ œ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๋ ค๋ฉด ๋‹ค์Œ ๋งํฌ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”:

๋Œ์•„๊ฐ€๊ธฐ

์„ค์น˜