Azure์์ ์๋ Queryable Encryption ์ฌ์ฉ
์ด ํ์ด์ง์ ๋ด์ฉ
- ๊ฐ์
- ์์ํ๊ธฐ ์ ์
- KMS ์ค์
- Azure์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋ก
- ๊ณ ๊ฐ ๋ง์คํฐ ํค ์์ฑ
- ์ ํ๋ฆฌ์ผ์ด์ ์์ฑ
- ํค ๋ณผํธ collection์ ๊ณ ์ ์ธ๋ฑ์ค ๋ง๋ค๊ธฐ
- ๋ฐ์ดํฐ ์ํธํ ํค ๋ฐ ์ํธํ๋ collection ๋ง๋ค๊ธฐ
- ์ํธํ๋ ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ๋ฅผ ์ํ MongoClient ๊ตฌ์ฑ
- ์ํธํ๋ ํ๋๊ฐ ์๋ ๋ฌธ์ ์ฝ์ ํ๊ธฐ
- ์ํธํ๋ ๋ฌธ์ ์กฐํ
- ์์ธํ ์์๋ณด๊ธฐ
๊ฐ์
์ด ๊ฐ์ด๋์์๋ Azure Key Vault๋ฅผ ์ฌ์ฉํ์ฌ Queryable Encryption ์ง์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น๋ํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค.
์ด ๊ฐ์ด๋์ ๋จ๊ณ๋ฅผ ์๋ฃํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ด์ฉ์ด ํ์๋ฉ๋๋ค:
Azure Key Vault ์ธ์คํด์ค์์ ํธ์คํ ๋๋ ๊ณ ๊ฐ ๋ง์คํฐ ํค์ ๋๋ค.
๊ณ ๊ฐ ๋ง์คํฐ ํค๋ฅผ ์ฌ์ฉํ์ฌ ์ํธํ๋ ๋ฌธ์๋ฅผ ์ฝ์ ํ๋ ์๋ํ๋ ํด๋ผ์ด์ธํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค.
์์ํ๊ธฐ ์ ์
์ด ๊ฐ์ด๋ ์ ์ฝ๋๋ฅผ ์๋ฃํ๊ณ ์คํ ํ๋ ค๋ฉด ์ค์น ์๊ตฌ ์ฌํญ ํ์ด์ง์ ํ์๋ ๋๋ก ๊ฐ๋ฐ ํ๊ฒฝ์ ์ค์ ํ๋ค ํด์ผ ํฉ๋๋ค.
ํ
์ฐธ์กฐ: ์ ์ฒด ์ ์ฉ
์ด ๊ฐ์ด๋์์ ๋ง๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ํด๋นํ๋ ํญ์ ์ ํํ๊ณ ์ ๊ณต๋ ๋งํฌ๋ฅผ ๋ฐ๋ผ๊ฐ์ธ์.
KMS ์ค์
Azure์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋ก
Azure ์ ๋ก๊ทธ์ธํฉ๋๋ค.
Azure Active Directory์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋ก
Azure Active Directory์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฑ๋กํ๋ ค๋ฉด Microsoft์ ๊ณต์ Microsoft ID ํ๋ซํผ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋กํ๊ธฐ ๋ฅผ ๋ฐ๋ฅด์ธ์. ๋น ๋ฅธ ์์.
์ค์
์๊ฒฉ ์ฆ๋ช ๊ธฐ๋ก
๋ค์ ์๊ฒฉ ์ฆ๋ช ์ ๊ธฐ๋กํด์ผ ํฉ๋๋ค.
ํ ๋ํธ ID
ํด๋ผ์ด์ธํธ ID
ํด๋ผ์ด์ธํธ ๋น๋ฐ
์ด ํํ ๋ฆฌ์ผ์ ๋ท๋ถ๋ถ์์ kmsProviders
๊ฐ์ฒด๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ ํ์ํฉ๋๋ค.
๊ณ ๊ฐ ๋ง์คํฐ ํค ์์ฑ
Azure Key Vault ๋ฐ ๊ณ ๊ฐ ๋ง์คํฐ ํค ๋ง๋ค๊ธฐ
์ Azure Key Vault ์ธ์คํด์ค ๋ฐ ๊ณ ๊ฐ ๋ง์คํฐ ํค๋ฅผ ๋ง๋ค๋ ค๋ฉด Microsoft์ ๊ณต์ ์ค์ ์ ๋ฐ๋ผ Azure Portal์ ์ฌ์ฉํ์ฌ Azure Key Vault์์ ํค๋ฅผ ๊ฒ์ํฉ๋๋ค. ๋น ๋ฅธ ์์.
์ค์
์๊ฒฉ ์ฆ๋ช ๊ธฐ๋ก
๋ค์ ์๊ฒฉ ์ฆ๋ช ์ ๊ธฐ๋กํด์ผ ํฉ๋๋ค.
ํค ์ด๋ฆ
ํค ์๋ณ์ (์ด ๊ฐ์ด๋ ๋ท๋ถ๋ถ์์
keyVaultEndpoint
์ด๋ผ๊ณ ํจ)keyVersion
์ด ํํ ๋ฆฌ์ผ์ ๋ท๋ถ๋ถ์์ dataKeyOpts
๊ฐ์ฒด๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ ํ์ํฉ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์์ฑ
ํค ๋ณผํธ collection์ ๊ณ ์ ์ธ๋ฑ์ค ๋ง๋ค๊ธฐ
collection์ ํ๋์ ๊ณ ์ ์ธ๋ฑ์ค๋ฅผ ์์ฑํฉ๋๋ค.keyAltNames
encryption.__keyVault
์ ํธํ๋ MongoDB ๋๋ผ์ด๋ฒ์ ํด๋นํ๋ ํญ์ ์ ํํฉ๋๋ค:
const uri = "<Your Connection String>"; const keyVaultClient = Mongo(uri); const keyVaultDB = keyVaultClient.getDB(keyVaultDatabase); // Drop the Key Vault Collection in case you created this collection // in a previous run of this application. keyVaultDB.dropDatabase(); keyVaultDB.createCollection(keyVaultCollection); const keyVaultColl = keyVaultDB.getCollection(keyVaultCollection); keyVaultColl.createIndex( { keyAltNames: 1 }, { unique: true, partialFilterExpression: { keyAltNames: { $exists: true } }, } );
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);
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 connectionString = "<Your MongoDB URI>"; 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}}, )
๋ฐ์ดํฐ ์ํธํ ํค ๋ฐ ์ํธํ๋ collection ๋ง๋ค๊ธฐ
Azure Key Vault ์๊ฒฉ ์ฆ๋ช ์ถ๊ฐ
Queryable Encryption์ด ํ์ฑํ๋ ํด๋ผ์ด์ธํธ ์ฝ๋์ ์๋น์ค ๊ณ์ ์๊ฒฉ ์ฆ๋ช ์ ์ถ๊ฐํฉ๋๋ค.
์ ํธํ๋ MongoDB ๋๋ผ์ด๋ฒ์ ํด๋นํ๋ ํญ์ ์ ํํฉ๋๋ค:
ํ
์ด ๊ฐ์ด๋์ Azure์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฑ๋ก ๋จ๊ณ์์ Azure Key Vault ์๊ฒฉ ์ฆ๋ช ์ ๊ธฐ๋กํ์ต๋๋ค.
const provider = "azure"; const kmsProviders = { azure: { tenantId: "<Your Tenant ID>", clientId: "<Your Client ID>", clientSecret: "<Your Client Secret>", }, };
var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>(); const string provider = "azure"; var azureKmsOptions = new Dictionary<string, object> { { "tenantId", "<Your Azure Tenant ID>" }, { "clientId", "<Your Azure Client ID>" }, { "clientSecret", "<Your Azure Client Secret>" }, }; kmsProviders.Add(provider, azureKmsOptions);
provider := "azure" kmsProviders := map[string]map[string]interface{}{ provider: { "tenantId": "<Your Azure Tenant ID>", "clientId": "<Your Azure Client ID>", "clientSecret": "<Your Azure Client Secret>", }, }
String kmsProvider = "azure"; Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>(); Map<String, Object> providerDetails = new HashMap<>(); providerDetails.put("tenantId", "<Azure account organization>"); providerDetails.put("clientId", "<Azure client ID>"); providerDetails.put("clientSecret", "<Azure client secret>"); kmsProviders.put(kmsProvider, providerDetails);
const provider = "azure"; const kmsProviders = { azure: { tenantId: "<Your Tenant ID>", clientId: "<Your Client ID>", clientSecret: "<Your Client Secret>", }, };
provider = "azure" kms_providers = { provider: { "tenantId": "<Azure account organization>", "clientId": "<Azure client ID>", "clientSecret": "<Azure client secret>", } }
ํ
์์ธํ ์์๋ณด๊ธฐ
Azure Key Vault์ KMS ์ ๊ณต์ ๊ฐ์ฒด์ ๋ํด ์์ธํ ์์๋ณด๋ ค๋ฉด Azure Key Vault๋ฅผ ์ฐธ์กฐํ์ธ์ .
ํค ์ ๋ณด ์ถ๊ฐ
๊ณ ๊ฐ ๋ง์คํฐ ํค๋ฅผ ์ง์ ํ๋ ค๋ฉด ๋ค์ ์ฝ๋๋ฅผ ์ ๋ฐ์ดํธํ์ธ์.
ํ
์ด ๊ฐ์ด๋ ์ ๊ณ ๊ฐ ๋ง์คํฐ ํค ์์ฑ ๋จ๊ณ์์ ๊ณ ๊ฐ ๋ง์คํฐ ํค์ ARN๋ฐ ๋ฆฌ์ ์ ๊ธฐ๋กํ์ต๋๋ค.
const masterKey = { keyVaultEndpoint: "<Your Key Vault Endpoint>", keyName: "<Your Key Name>", };
DataKeyOptions GetDataKeyOptions(List<string> altNames) { kmsProviders.Add(provider, azureKmsOptions); var dataKeyOptions = new DataKeyOptions( alternateKeyNames: altNames, masterKey: new BsonDocument { { "keyName", "<Your Azure Key Name>" }, { "keyVaultEndpoint", "<Your Azure Key Vault Endpoint>" }, }); return dataKeyOptions; }
masterKey := map[string]interface{}{ "keyVaultEndpoint": "<Your Azure Key Vault Endpoint>", "keyName": "<Your Azure Key Name>", }
BsonDocument masterKeyProperties = new BsonDocument(); masterKeyProperties.put("provider", new BsonString(kmsProvider)); masterKeyProperties.put("keyName", new BsonString("<Azure key name>")); masterKeyProperties.put("keyVaultEndpoint", new BsonString("<Azure key vault endpoint"));
const masterKey = { keyVaultEndpoint: "<Your Key Vault Endpoint>", keyName: "<Your Key Name>", };
master_key = { "keyName": "<Azure key name>", "keyVersion": "<Azure key version>", "keyVaultEndpoint": "<Azure key vault endpoint/key identifier>", }
๋ฐ์ดํฐ ์ํธํ ํค ๋ง๋ค๊ธฐ
MongoDB ์ฐ๊ฒฐ ๋ฌธ์์ด๊ณผ ํค ๋ณผํธ ์ปฌ๋ ์ ๋ค์์คํ์ด์ค๋ฅผ ์ฌ์ฉํ์ฌ ํด๋ผ์ด์ธํธ๋ฅผ ๊ตฌ์ฑํ๊ณ ๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ๋ง๋ญ๋๋ค.
์ฐธ๊ณ
ํค ๋ณผํธ ์ปฌ๋ ์ ๋ค์์คํ์ด์ค ๊ถํ
์ด ๊ฐ์ด๋์ ํค ๋ณผํธ ์ปฌ๋ ์
์ encryption
๋ฐ์ดํฐ๋ฒ ์ด์ค์ __keyVault
์ปฌ๋ ์
์
๋๋ค. ์ ํ๋ฆฌ์ผ์ด์
์์ MongoDB์ ์ฐ๊ฒฐํ๋ ๋ฐ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ์์๊ฒ encryption.__keyVault
๋ค์์คํ์ด์ค์ ๋ํ ReadWrite ๊ถํ์ด ์๋์ง ํ์ธํฉ๋๋ค.
const autoEncryptionOpts = { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, }; const encClient = Mongo(uri, autoEncryptionOpts); const keyVault = encClient.getKeyVault(); const dek1 = keyVault.createKey(provider, { masterKey: masterKey, keyAltNames: ["dataKey1"], }); const dek2 = keyVault.createKey(provider, { masterKey: masterKey, keyAltNames: ["dataKey2"], }); const dek3 = keyVault.createKey(provider, { masterKey: masterKey, keyAltNames: ["dataKey3"], }); const dek4 = keyVault.createKey(provider, { masterKey: masterKey, keyAltNames: ["dataKey4"], });
var clientEncryptionOptions = new ClientEncryptionOptions( keyVaultClient, keyVaultNamespace, kmsProviders: kmsProviders ); var clientEncryption = new ClientEncryption(clientEncryptionOptions); var dataKeyOptions1 = GetDataKeyOptions(new List<string> { "dataKey1" }); var dataKeyOptions2 = GetDataKeyOptions(new List<string> { "dataKey2" }); var dataKeyOptions3 = GetDataKeyOptions(new List<string> { "dataKey3" }); var dataKeyOptions4 = GetDataKeyOptions(new List<string> { "dataKey4" }); 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(). SetMasterKey(masterKey). 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(). SetMasterKey(masterKey). SetKeyAltNames([]string{"demoDataKey2"}) dataKeyID2, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts2) if err != nil { return fmt.Errorf("create data key error %v", err) } dataKeyOpts3 := options.DataKey(). SetMasterKey(masterKey). SetKeyAltNames([]string{"demoDataKey3"}) dataKeyID3, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts3) if err != nil { return fmt.Errorf("create data key error %v", err) } dataKeyOpts4 := options.DataKey(). SetMasterKey(masterKey). SetKeyAltNames([]string{"demoDataKey4"}) dataKeyID4, err := clientEnc.CreateDataKey(context.TODO(), provider, dataKeyOpts4) 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() .masterKey(masterKeyProperties) .keyAltNames(keyAlts1)); List<String> keyAlts2 = new ArrayList<String>(); keyAlts2.add("dataKey2"); BsonBinary dataKeyId2 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions() .masterKey(masterKeyProperties) .keyAltNames(keyAlts2)); List<String> keyAlts3 = new ArrayList<String>(); keyAlts3.add("dataKey3"); BsonBinary dataKeyId3 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions() .masterKey(masterKeyProperties) .keyAltNames(keyAlts3)); List<String> keyAlts4 = new ArrayList<String>(); keyAlts4.add("dataKey4"); BsonBinary dataKeyId4 = clientEncryption.createDataKey(kmsProvider, new DataKeyOptions() .masterKey(masterKeyProperties) .keyAltNames(keyAlts4));
const clientEnc = new ClientEncryption(keyVaultClient, { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, }); const dek1 = await clientEnc.createDataKey(provider, { masterKey: masterKey, keyAltNames: ["dataKey1"], }); const dek2 = await clientEnc.createDataKey(provider, { masterKey: masterKey, keyAltNames: ["dataKey2"], }); const dek3 = await clientEnc.createDataKey(provider, { masterKey: masterKey, keyAltNames: ["dataKey3"], }); const dek4 = await clientEnc.createDataKey(provider, { masterKey: masterKey, keyAltNames: ["dataKey4"], });
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, master_key=master_key, key_alt_names=["dataKey1"] ) data_key_id_2 = client_encryption.create_data_key( provider, master_key=master_key, key_alt_names=["dataKey2"] ) data_key_id_3 = client_encryption.create_data_key( provider, master_key=master_key, key_alt_names=["dataKey3"] ) data_key_id_4 = client_encryption.create_data_key( provider, master_key=master_key, key_alt_names=["dataKey4"] )
์ํธํ๋ ์ปฌ๋ ์ ๋ง๋ค๊ธฐ
Queryable Encryption์ด ํ์ฑํ๋ MongoClient
์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ์ฌ ํ๋๋ฅผ ์ง์ ํ๊ณ ์ํธํ๋ collection์ ์์ฑํฉ๋๋ค.
const encryptedFieldsMap = { [`${secretDB}.${secretCollection}`]: { fields: [ { keyId: dek1, path: "patientId", bsonType: "int", queries: { queryType: "equality" }, }, { keyId: dek2, path: "medications", bsonType: "array", }, { keyId: dek3, path: "patientRecord.ssn", bsonType: "string", queries: { queryType: "equality" }, }, { keyId: dek4, path: "patientRecord.billing", bsonType: "object", }, ], }, }; try { const autoEncryptionOptions = { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, encryptedFieldsMap: encryptedFieldsMap, }; const encClient = Mongo(uri, autoEncryptionOptions); const newEncDB = encClient.getDB(secretDB); // Drop the encrypted collection in case you created this collection // in a previous run of this application. newEncDB.dropDatabase(); newEncDB.createCollection(secretCollection); console.log("Created encrypted 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")}, }, new BsonDocument { {"keyId", dataKeyId3}, {"path", new BsonString("patientRecord.ssn")}, {"bsonType", new BsonString("string")}, { "queries", new BsonDocument { {"queryType", new BsonString("equality")} } } }, new BsonDocument { {"keyId", dataKeyId4}, {"path", new BsonString("patientRecord.billing")}, {"bsonType", new BsonString("object")}, }, } } } } }; 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, }, { "path": "patientRecord.ssn", "bsonType": "string", "keyId": dataKeyID3, "queries": []bson.M{ { "queryType": "equality", }, }, }, { "path": "patientRecord.billing", "bsonType": "object", "keyId": dataKeyID4, }, }, }, } 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")), new BsonDocument().append("keyId", dataKeyId3) .append("path", new BsonString("patientRecord.ssn")) .append("bsonType", new BsonString("string")) .append("queries", new BsonDocument().append("queryType", new BsonString("equality"))), new BsonDocument().append("keyId", dataKeyId4) .append("path", new BsonString("patientRecord.billing")) .append("bsonType", new BsonString("object")) ))); 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", }, { keyId: dek3, path: "patientRecord.ssn", bsonType: "string", queries: { queryType: "equality" }, }, { keyId: dek4, path: "patientRecord.billing", bsonType: "object", }, ], }, }; 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", }, { "keyId": data_key_id_3, "path": "patientRecord.ssn", "bsonType": "string", "queries": {"queryType": "equality"}, }, { "keyId": data_key_id_4, "path": "patientRecord.billing", "bsonType": "object", }, ], }, } key_vault_namespace = "encryption.__keyVault" auto_encryption = AutoEncryptionOpts( kms_providers, key_vault_namespace, encrypted_fields_map=encrypted_fields_map, schema_map=None, 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!")
ํ
์์ธํ ์์๋ณด๊ธฐ
Azure Key Vault๋ฅผ ์ฌ์ฉํ ๋ ํด๋ผ์ด์ธํธ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ฃผ๋ ๋ค์ด์ด๊ทธ๋จ์ ๋ณด๋ ค๋ฉด ์ํคํ ์ฒ๋ฅผ ์ฐธ์กฐํ์ธ์.
Azure Key Vault์์ ํธ์คํ ๋๋ ๊ณ ๊ฐ ๋ง์คํฐ ํค๋ก ์ํธํ๋ ๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ์์ฑํ๋ ์ต์ ์ ๋ํด ์์ธํ ์์๋ณด๋ ค๋ฉด kmsProviders ๊ฐ์ฒด ๋ฐ dataKeyOpts ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ์ธ์.
ํ
์ฐธ์กฐ: ์ฝ๋ ์์ฑ
๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ๋ง๋ค๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ๋ง๋ค๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ๋ง๋ค๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ๋ง๋ค๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ๋ง๋ค๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ฐ์ดํฐ ์ํธํ ํค๋ฅผ ๋ง๋ค๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ๋ฅผ ์ํ MongoClient ๊ตฌ์ฑ
ํค ๋ณผํธ collection ๋ค์์คํ์ด์ค ์ง์ ํ๊ธฐ
ํค ๋ณผํธ collection ๋ค์์คํ์ด์ค๋ก encryption.__keyVault
์ ์ง์ ํฉ๋๋ค.
const keyVaultDB = "encryption"; const keyVaultColl = "__keyVault"; const keyVaultNamespace = `${keyVaultDB}.${keyVaultColl}`; const secretDB = "medicalRecords"; const secretCollection = "patients";
var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVault");
keyVaultColl := "__keyVault" keyVaultDb := "encryption" keyVaultNamespace := keyVaultDb + "." + keyVaultColl
String keyVaultDb = "encryption"; String keyVaultColl = "__keyVault"; String keyVaultNamespace = keyVaultDb + "." + keyVaultColl;
const eDB = "encryption"; const eKV = "__keyVault"; const keyVaultNamespace = `${eDB}.${eKV}`;
key_vault_db = "encryption" key_vault_coll = "__keyVault" key_vault_namespace = "encryption.__keyVault"
Azure ์๊ฒฉ ์ฆ๋ช ์ง์
azure
KMS ์ ๊ณต์์ Azure ์๊ฒฉ ์ฆ๋ช
์ ์ง์ ํฉ๋๋ค.
const kmsProviders = { azure: { tenantId: "<Your Tenant ID>", clientId: "<Your Client ID>", clientSecret: "<Your Client Secret>", }, };
var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>(); const string provider = "azure"; var azureKmsOptions = new Dictionary<string, object> { { "tenantId", "<Your Azure Tenant ID>" }, { "clientId", "<Your Azure Client ID>" }, { "clientSecret", "<Your Azure Client Secret>" }, }; kmsProviders.Add(provider, azureKmsOptions);
kmsProviders := map[string]map[string]interface{}{ "azure": { "tenantId": "<Your Azure Tenant ID>", "clientId": "<Your Azure Client ID>", "clientSecret": "<Your Azure Client Secret>", }, }
String kmsProvider = "azure"; Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>(); Map<String, Object> providerDetails = new HashMap<>(); providerDetails.put("tenantId", "<Azure account organization>"); providerDetails.put("clientId", "<Azure client ID>"); providerDetails.put("clientSecret", "<Azure client secret>"); kmsProviders.put(kmsProvider, providerDetails);
const kmsProviders = { azure: { tenantId: "<Your Tenant ID>", clientId: "<Your Client ID>", clientSecret: "<Your Client Secret>", }, };
provider = "azure" kms_providers = { provider: { "tenantId": "<Azure account organization>", "clientId": "<Azure client ID>", "clientSecret": "<Azure client secret>", } }
collection์ ์ํ ์ํธํ๋ ํ๋ ๋งต ๋ง๋ค๊ธฐ
const uri = "<Your Connection String>"; const unencryptedClient = Mongo(uri); const autoEncryptionOpts = { kmsProviders, keyVaultNamespace }; const encClient = Mongo(uri, autoEncryptionOpts); const keyVault = encClient.getKeyVault(); const keyVaultClient = unencryptedClient .getDB(keyVaultDB) .getCollection(keyVaultColl); const dek1 = keyVaultClient.findOne({ keyAltNames: "dataKey1" }); const dek2 = keyVaultClient.findOne({ keyAltNames: "dataKey2" }); const dek3 = keyVaultClient.findOne({ keyAltNames: "dataKey3" }); const dek4 = keyVaultClient.findOne({ keyAltNames: "dataKey4" }); const secretDB = "medicalRecords"; const secretColl = "patients"; const encryptedFieldsMap = { [`${secretDB}.${secretColl}`]: { fields: [ { keyId: dek1._id, path: "patientId", bsonType: "int", queries: { queryType: "equality" }, }, { keyId: dek2._id, path: "medications", bsonType: "array", }, { keyId: dek3._id, path: "patientRecord.ssn", bsonType: "string", queries: { queryType: "equality" }, }, { keyId: dek4._id, path: "patientRecord.billing", bsonType: "object", }, ], }, };
var regularClient = new MongoClient(connectionString); var keyVaultCollection = regularClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName) .GetCollection<BsonDocument>(keyVaultNamespace.CollectionName); BsonBinaryData GetKeyId(string altName) { var filter = Builders<BsonDocument>.Filter.Eq<BsonString>("keyAltNames", altName); return keyVaultCollection.Find(filter).First<BsonDocument>()["_id"].AsBsonBinaryData; } var dataKeyId1 = GetKeyId("dataKey1"); var dataKeyId2 = GetKeyId("dataKey2"); var dataKeyId3 = GetKeyId("dataKey3"); var dataKeyId4 = GetKeyId("dataKey4"); 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")}, }, new BsonDocument { {"keyId", dataKeyId3}, {"path", new BsonString("patientRecord.ssn")}, {"bsonType", new BsonString("string")}, { "queries", new BsonDocument { {"queryType", new BsonString("equality")} } } }, new BsonDocument { {"keyId", dataKeyId4}, {"path", new BsonString("patientRecord.billing")}, {"bsonType", new BsonString("object")}, }, } } } } };
regularClient, err := mongo.Connect(context.TODO(), options.Client().ApplyURI(uri)) if err != nil { return fmt.Errorf("Connect error for regular client: %v", err) } defer func() { _ = regularClient.Disconnect(context.TODO()) }() 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) var foundDoc3 bson.M err = regularClient.Database(keyVaultDb).Collection(keyVaultColl).FindOne(context.TODO(), bson.D{{"keyAltNames", "demoDataKey3"}}).Decode(&foundDoc3) if err != nil { panic(err) } var dataKeyID3 = foundDoc3["_id"].(primitive.Binary) var foundDoc4 bson.M err = regularClient.Database(keyVaultDb).Collection(keyVaultColl).FindOne(context.TODO(), bson.D{{"keyAltNames", "demoDataKey4"}}).Decode(&foundDoc4) if err != nil { panic(err) } var dataKeyID4 = foundDoc4["_id"].(primitive.Binary) encryptedFieldsMap := bson.M{ "medicalRecords.patients": bson.M{ "fields": []bson.M{ { "path": "patientId", "bsonType": "int", "keyId": dataKeyID1, "queries": []bson.M{ { "queryType": "equality", }, }, }, { "path": "medications", "bsonType": "array", "keyId": dataKeyID2, }, { "path": "patientRecord.ssn", "bsonType": "string", "keyId": dataKeyID3, "queries": []bson.M{ { "queryType": "equality", }, }, }, { "path": "patientRecord.billing", "bsonType": "object", "keyId": dataKeyID4, }, }, }, }
MongoClient regularClient = MongoClients.create(connectionString); MongoCollection<Document> keyVaultClient = regularClient.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()); BsonBinary dataKeyId3 = new BsonBinary(BsonBinarySubType.UUID_STANDARD, keyVaultClient.find(eq("keyAltNames", "dataKey3")).first().get("_id", Binary.class).getData()); BsonBinary dataKeyId4 = new BsonBinary(BsonBinarySubType.UUID_STANDARD, keyVaultClient.find(eq("keyAltNames", "dataKey4")).first().get("_id", Binary.class).getData()); 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")), new BsonDocument().append("keyId", dataKeyId3) .append("path", new BsonString("patientRecord.ssn")) .append("bsonType", new BsonString("string")) .append("queries", new BsonDocument().append("queryType", new BsonString("equality"))), new BsonDocument().append("keyId", dataKeyId4) .append("path", new BsonString("patientRecord.billing")) .append("bsonType", new BsonString("object"))))); Map<String, BsonDocument> encryptedFieldsMap = new HashMap<String, BsonDocument>(); encryptedFieldsMap.put(encryptedNameSpace, encFields);
const uri = "<Your Connection String>"; 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" }); const dek3 = await keyVaultClient.findOne({ keyAltNames: "dataKey3" }); const dek4 = await keyVaultClient.findOne({ keyAltNames: "dataKey4" }); const secretDB = "medicalRecords"; const secretCollection = "patients"; const encryptedFieldsMap = { [`${secretDB}.${secretCollection}`]: { fields: [ { keyId: dek1._id, path: "patientId", bsonType: "int", queries: { queryType: "equality" }, }, { keyId: dek2._id, path: "medications", bsonType: "array", }, { keyId: dek3._id, path: "patientRecord.ssn", bsonType: "string", queries: { queryType: "equality" }, }, { keyId: dek4._id, path: "patientRecord.billing", bsonType: "object", }, ], }, };
connection_string = "<your connection string here>" unencryptedClient = MongoClient(connection_string) keyVaultClient = unencryptedClient[key_vault_db][key_vault_coll] data_key_id_1 = keyVaultClient.find_one({"keyAltNames": "dataKey1"})["_id"] data_key_id_2 = keyVaultClient.find_one({"keyAltNames": "dataKey2"})["_id"] data_key_id_3 = keyVaultClient.find_one({"keyAltNames": "dataKey3"})["_id"] data_key_id_4 = keyVaultClient.find_one({"keyAltNames": "dataKey4"})["_id"] 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", }, { "keyId": data_key_id_3, "path": "patientRecord.ssn", "bsonType": "string", "queries": {"queryType": "equality"}, }, { "keyId": data_key_id_4, "path": "patientRecord.billing", "bsonType": "object", }, ], }, }
์๋ ์ํธํ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์น ์ง์
// mongosh does not require you to specify the // location of the Automatic Encryption Shared Library
var extraOptions = new Dictionary<string, object>() { { "cryptSharedLibPath", "<path to crypt_shared library>" }, };
extraOptions := map[string]interface{}{ "cryptSharedLibPath": "<Your Crypt Shared lib Path>", }
Map<String, Object> extraOptions = new HashMap<String, Object>(); extraOptions.put("cryptSharedLibPath", "<path to crypt_shared>");
const extraOptions = { cryptSharedLibPath: "<path to FLE Shared Library>", };
auto_encryption = AutoEncryptionOpts( kms_providers, key_vault_namespace, encrypted_fields_map=encrypted_fields_map, schema_map=None, crypt_shared_lib_path="<path to FLE Shared Library>", )
์ฐธ๊ณ
์๋ ์ํธํ ์ต์
์๋ ์ํธํ ์ต์ ์ ์๋ ์ํธํ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ฌ ์ํธํ๋ ํ๋์ ์ก์ธ์คํ ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์์ ์์ ํฉ๋๋ค.
์๋ ์ํธํ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ํ ์์ธํ ๋ด์ฉ์ Queryable Encryption์ ์ํ ์๋ ์ํธํ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ด์ง์์ ํ์ธํ์ธ์.
MongoClient ์์ฑ
๋ค์ ์๋ ์ํธํ ์ค์ ์ ์ฌ์ฉํ์ฌ MongoDB ํด๋ผ์ด์ธํธ ๊ฐ์ฒด๋ฅผ ์ธ์คํด์คํํฉ๋๋ค.
const autoEncryptionOptions = { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, bypassQueryAnalysis: false, encryptedFieldsMap: encryptedFieldsMap, }; const encryptedClient = Mongo(uri, autoEncryptionOptions); const encryptedColl = encryptedClient .getDB(secretDB) .getCollection(secretColl); const unencryptedColl = unencryptedClient .getDB(secretDB) .getCollection(secretColl);
var clientSettings = MongoClientSettings.FromConnectionString(connectionString); var autoEncryptionOptions = new AutoEncryptionOptions( keyVaultNamespace, kmsProviders, encryptedFieldsMap: encryptedFieldsMap, extraOptions: extraOptions ); clientSettings.AutoEncryptionOptions = autoEncryptionOptions; var secureClient = new MongoClient(clientSettings);
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()) }()
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);
const encryptedClient = new MongoClient(uri, { autoEncryption: { keyVaultNamespace: keyVaultNamespace, kmsProviders: kmsProviders, extraOptions: extraOptions, encryptedFieldsMap: encryptedFieldsMap, }, }); await encryptedClient.connect();
secure_client = MongoClient(connection_string, auto_encryption_opts=auto_encryption)
์ํธํ๋ ํ๋๊ฐ ์๋ ๋ฌธ์ ์ฝ์ ํ๊ธฐ
Queryable Encryption์ด ํ์ฑํ๋ MongoClient
์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ ์ฝ๋ ์ค๋ํซ์ ์ฌ์ฉํ์ฌ ์ํธํ๋ ๋ฌธ์๋ฅผ medicalRecords.patients
๋ค์์คํ์ด์ค์ ์ฝ์
ํฉ๋๋ค.
encryptedColl.insertOne({ firstName: "Jon", lastName: "Doe", patientId: 12345678, address: "157 Electric Ave.", patientRecord: { ssn: "987-65-4320", billing: { type: "Visa", number: "4111111111111111", }, }, medications: ["Atorvastatin", "Levothyroxine"], });
var sampleDocument = new BsonDocument { {"firstName", "Jon"}, {"lastName", "Doe"}, {"patientId", 12345678}, {"address", "157 Electric Ave."}, { "medications", new BsonArray { new BsonString("Atorvastatin"), new BsonString("Levothyroxine") } }, { "patientRecord", new BsonDocument { {"ssn", new BsonString("987-65-4320")}, { "billing", new BsonDocument { {"type", new BsonString("Visa")}, {"number", "4111111111111111"} } } } } }; var secureCollection = secureClient.GetDatabase(encryptedCollectionNamespace.DatabaseNamespace.DatabaseName) .GetCollection<BsonDocument>(encryptedCollectionNamespace.CollectionName); secureCollection.InsertOne(sampleDocument);
test_patient := map[string]interface{}{ "firstName": "Jon", "lastName": "Doe", "patientId": 12345678, "address": "157 Electric Ave.", "medications": []string{"Atorvastatin", "Levothyroxine"}, "patientRecord": map[string]interface{}{ "ssn": "987-65-4320", "billing": map[string]interface{}{ "type": "Visa", "number": "4111111111111111", }, }, } if _, err := secureClient.Database(dbName).Collection(collName).InsertOne(context.TODO(), test_patient); err != nil { return fmt.Errorf("InsertOne error: %v", err) }
ArrayList<String> medications = new ArrayList<>(); medications.add("Atorvastatin"); medications.add("Levothyroxine"); Document patientRecord = new Document() .append("ssn", "987-65-4320") .append("billing", new Document().append("type", "Visa").append("number", "4111111111111111")); Document patient = new Document() .append("firstName", "Jon") .append("lastName", "Doe") .append("patientId", 12345678) .append("address", "AB+") .append("medications", medications) .append("patientRecord", patientRecord); mongoClientSecure.getDatabase(encryptedDbName).getCollection(encryptedCollName).insertOne(patient);
const encryptedColl = encryptedClient .db(secretDB) .collection(secretCollection); await encryptedColl.insertOne({ firstName: "Jon", lastName: "Doe", patientId: 12345678, address: "157 Electric Ave.", patientRecord: { ssn: "987-65-4320", billing: { type: "Visa", number: "4111111111111111", }, }, medications: ["Atorvastatin", "Levothyroxine"], });
์ฐธ๊ณ
์์ BSON ๋ฌธ์๋ฅผ ๋ง๋๋ ๋์ bson
ํ๊ทธ๊ฐ ์๋ ๊ตฌ์กฐ์ฒด๋ฅผ ๋๋ผ์ด๋ฒ์ ์ง์ ์ ๋ฌํ์ฌ ์ธ์ฝ๋ฉํ ์ ์์ต๋๋ค.
encrypted_coll = secure_client[encrypted_db_name][encrypted_coll_name] encrypted_coll.insert_one( { "firstName": "Jon", "lastName": "Doe", "patientId": 12345678, "address": "157 Electric Ave.", "patientRecord": { "ssn": "987-65-4320", "billing": { "type": "Visa", "number": "4111111111111111", }, }, "medications": ["Atorvastatin", "Levothyroxine"], } )
๋ฌธ์๋ฅผ ์ฝ์ ํ๋ฉด Queryable Encryption์ด ํ์ฑํ๋ ํด๋ผ์ด์ธํธ๊ฐ ๋ค์๊ณผ ๊ฐ์ด ๋ฌธ์์ ํ๋๋ฅผ ์ํธํํฉ๋๋ค.
{ "_id": { "$oid": "<_id value>" }, "firstName": "Jon", "lastName": "Doe", "patientId": { "$binary": { "base64": "<ciphertext>", "subType": "06" } }, "address": "157 Electric Ave.", "patientRecord": { "ssn": { "$binary": { "base64": "<ciphertext>", "subType": "06" } }, "billing": { "$binary": { "base64": "<ciphertext>", "subType": "06" } } }, "medications": { "$binary": { "base64": "<ciphertext>", "subType": "06" } }, "__safeContent__": [ { "$binary": { "base64": "<ciphertext>", "subType": "00" } }, { "$binary": { "base64": "<ciphertext>", "subType": "00" } } ] }
๊ฒฝ๊ณ
__safeContent__ ํ๋๋ฅผ ์์ ํ์ง ๋ง์ธ์.
__safeContent__
ํ๋๋ Queryable Encryption์ ๋ฐ๋์ ํ์ํฉ๋๋ค. ์ด ํ๋์ ๋ด์ฉ์ ์์ ํ์ง ๋ง์ธ์.
ํ
์ฐธ์กฐ: ์ฝ๋ ์์ฑ
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฝ์ ํ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฝ์ ํ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฝ์ ํ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฝ์ ํ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฝ์ ํ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฝ์ ํ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์ ์กฐํ
์ด ๊ฐ์ด๋์ ์ํธํ๋ ํ๋๊ฐ ์๋ ๋ฌธ์ ์ฝ์ ๋จ๊ณ์์ ์ฝ์ ํ ์ํธํ๋ ๋ฌธ์๋ฅผ ๊ฒ์ํฉ๋๋ค.
Queryable Encryption์ ๊ธฐ๋ฅ์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ๋ค์ ์ฝ๋ ์ค๋ํซ์ ์๋ Queryable Encryption์ผ๋ก ๊ตฌ์ฑ๋ ํด๋ผ์ด์ธํธ์ ์๋ Queryable Encryption์ด ๊ตฌ์ฑ๋์ง ์์ ํด๋ผ์ด์ธํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์๋ฅผ ์ฟผ๋ฆฌํฉ๋๋ค.
console.log("Finding a document with regular (non-encrypted) client."); console.log(unencryptedColl.findOne({ firstName: /Jon/ })); console.log( "Finding a document with encrypted client, searching on an encrypted field" ); console.log(encryptedColl.findOne({ "patientRecord.ssn": "987-65-4320" }));
Console.WriteLine("Finding a document with regular (non-encrypted) client."); var filter = Builders<BsonDocument>.Filter.Eq("firstName", "Jon"); var regularClientEncryptedCollection = regularClient.GetDatabase(encryptedCollectionNamespace.DatabaseNamespace.DatabaseName) .GetCollection<BsonDocument>(encryptedCollectionNamespace.CollectionName); var regularResult = regularClientEncryptedCollection.Find(filter).First(); Console.WriteLine($"\n{regularResult}\n"); Console.WriteLine("Finding a document with encrypted client, searching on an encrypted field"); var encryptedFieldFilter = Builders<BsonDocument>.Filter.Eq("patientRecord.ssn", "987-65-4320"); var secureResult = secureCollection.Find(encryptedFieldFilter).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{{"firstName", "Jon"}}).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, searching on an encrypted field") var resultSecure bson.M err = secureClient.Database(dbName).Collection(collName).FindOne(context.TODO(), bson.D{bson.E{"patientRecord.ssn", "987-65-4320"}}).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 = regularClient.getDatabase(encryptedDbName).getCollection(encryptedCollName).find(eq("firstName", "Jon")).first(); System.out.println(docRegular.toJson()); System.out.println("Finding a document with encrypted client, searching on an encrypted field"); Document docSecure = mongoClientSecure.getDatabase(encryptedDbName).getCollection(encryptedCollName).find(eq("patientRecord.ssn", "987-65-4320")).first(); System.out.println(docSecure.toJson());
console.log("Finding a document with regular (non-encrypted) client."); console.log(await unencryptedColl.findOne({ firstName: /Jon/ })); console.log( "Finding a document with encrypted client, searching on an encrypted field" ); console.log( await encryptedColl.findOne({ "patientRecord.ssn": "987-65-4320" }) );
print("Finding a document with regular (non-encrypted) client.") pprint.pprint( unencryptedClient[encrypted_db_name][encrypted_coll_name].find_one( {"firstName": "Jon"} ) ) print("Finding a document with encrypted client, searching on an encrypted field") pprint.pprint(encrypted_coll.find_one({"patientRecord.ssn": "987-65-4320"}))
์ด์ ์ฝ๋ ์ค๋ํซ์ ์ถ๋ ฅ์ ๋ค์๊ณผ ๊ฐ์์ผ ํฉ๋๋ค.
Finding a document with regular (non-encrypted) client. { _id: new ObjectId("628eabeb37590e84ea742665"), firstName: 'Jon', lastName: 'Doe', patientId: new Binary(Buffer.from("0798810acc0f4f46c9a76883cee80fca12102e9ddcbcdae46a821fa108a8155a850f2d0919475b6531ada68973d436a199b537a05a98a708c36d2bfec4979d59cbe66878865ce19e392d3e4789d309bdacc336e32efcc851806ae0a41b355288c10d01e39147e1c40d919c41913a0c9d2d3fad0d0d1d2873c4fc82c6c22f27b517df5f3131b331b96ed16a7c5cf89e09082a2d898c2dcd73da91d08760ba74a70077b2d0fdbbe1eea75655a19fcc397812325ad40b102cbd16b8d36b22e11e3f93404f24a8ff68cfdec3c22b0e787cb30078a5227b2a", "hex"), 6), address: '157 Electric Ave.', patientRecord: { ssn: new Binary(Buffer.from("07e8b69630c32f4a00a542af768f8abcf50223edd812ff20b0ecb046ee1a9f5a0eef8d85d99cd26076411129942752516ee605c55aadce73f3d44d81ea6ddbbb8134b108a9deb40d8cab9cb4f08ef210ab0c9d2ea4347f9d235b861baf29751e60abcf059eb5c120305bd5ac05a4e07ac8ccfa6d37283f4cdbfeb7a8accb65b71857d486b5cf55e354d6a95e287d9e2dd65f3f9d9c4c9d0bdb1f26c4bd549d7be77db81796be293e08b2223bac67b212423c4e06568578b5bd7a3c33cedc1b291bcda0b27e005144d344563711a489f24b8e9b65bbb721d3a0e9d9b227a0cec0cbad", "hex"), 6), billing: new Binary(Buffer.from("06808ae69d4caa49cf90bb688f386f097f03f870a7b8fcebb1980c9ee5488b1f0f68558fc2163adcd92d00ea5f349f56ed34e7b391f54c48ed2760b4bde73022fc818dc7486a4e046b92ce9c82e00333c7779d9d6bb476713a20632b593b7de54812662cfc4d174d05451d3f4195514e12edba", "hex"), 6) }, medications: new Binary(Buffer.from("06665ec15d38254dc4aa16da856789d33404f27bfea53e0d2fa4deaff166989ab33f469644d89c29112d33b41dbe54ec2d89c43f3de52cdc5d454e8694046216f533614fa7b42b7c5406d6518f7ed8f9e3ce52fda6c8b2146d0f8cc51e21a3467183697e1735a9f60c18e173c1916101", "hex"), 6), __safeContent__: [ new Binary(Buffer.from("3044b134ad0f7c8a90dab1e05bb8b296a8ede540796bd7403ab47693cdba1b26", "hex"), 0), new Binary(Buffer.from("a22ddf9a5657cdd56bef72febbba44371899e6486962a1c07d682082c4e65712", "hex"), 0) ] } Finding a document with encrypted client, searching on an encrypted field { _id: new ObjectId("628eaca1dcf9b63e2f43162d"), firstName: 'Jon', lastName: 'Doe', patientId: 12345678, address: '157 Electric Ave.', patientRecord: { ssn: '987-65-4320', billing: { type: 'Visa', number: '4111111111111111' } }, medications: [ 'Atorvastatin', 'Levothyroxine' ], __safeContent__: [ new Binary(Buffer.from("fbdc6cfe3b4659693650bfc60baced27dcb42b793efe09da0ded54d60a9d5a1f", "hex"), 0), new Binary(Buffer.from("0f92ff92bf904a858ef6fd5b1e508187f523e791f51d8b64596461b38ebb1791", "hex"), 0) ] }
ํ
์ฐธ์กฐ: ์ฝ๋ ์์ฑ
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฐพ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฐพ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฐพ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฐพ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฐพ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์ํธํ๋ ๋ฌธ์๋ฅผ ์ฐพ๊ธฐ ์ํ ์ ์ฒด ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด Queryable Encryption ์ํ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ์ฐธ์กฐํ์ธ์.
์์ธํ ์์๋ณด๊ธฐ
Queryable Encryption์ ์๋ ๋ฐฉ์์ ์์๋ณด๋ ค๋ฉด ๊ธฐ๋ณธ ์ฌํญ์ ์ฐธ์กฐํ์ธ์.
์ด ๊ฐ์ด๋์ ์ธ๊ธ๋ ์ฃผ์ ์ ๋ํด ์์ธํ ์์๋ณด๋ ค๋ฉด ๋ค์ ๋งํฌ๋ฅผ ์ฐธ์กฐํ์ธ์:
์ฐธ์กฐ ํ์ด์ง์์ Queryable Encryption ๊ตฌ์ฑ ์์์ ๋ํด ์์ธํ ์์๋ณด์ธ์.
ํค ๋ฐ ํค ๋ณผํธ ํ์ด์ง์์ ๊ณ ๊ฐ ๋ง์คํฐ ํค์ ๋ฐ์ดํฐ ์ํธํ ํค๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ์์๋ณด์ธ์.
KMS ์ ๊ณต์๊ฐ Queryable Encryption ํค๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ KMS ์ ๊ณต์ ํ์ด์ง์์ ํ์ธํ์ธ์.