1// Copyright (C) MongoDB, Inc. 2017-present. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may 4// not use this file except in compliance with the License. You may obtain 5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7package mongo 8 9import ( 10 "context" 11 "crypto/rand" 12 "encoding/base64" 13 "fmt" 14 "log" 15 16 "go.mongodb.org/mongo-driver/bson" 17 "go.mongodb.org/mongo-driver/mongo/options" 18) 19 20func Example_clientSideEncryption() { 21 // This would have to be the same master key that was used to create the encryption key 22 localKey := make([]byte, 96) 23 if _, err := rand.Read(localKey); err != nil { 24 log.Fatal(err) 25 } 26 kmsProviders := map[string]map[string]interface{}{ 27 "local": { 28 "key": localKey, 29 }, 30 } 31 keyVaultNamespace := "admin.datakeys" 32 33 uri := "mongodb://localhost:27017" 34 autoEncryptionOpts := options.AutoEncryption(). 35 SetKeyVaultNamespace(keyVaultNamespace). 36 SetKmsProviders(kmsProviders) 37 clientOpts := options.Client().ApplyURI(uri).SetAutoEncryptionOptions(autoEncryptionOpts) 38 client, err := Connect(context.TODO(), clientOpts) 39 if err != nil { 40 log.Fatalf("Connect error: %v", err) 41 } 42 defer func() { 43 if err = client.Disconnect(context.TODO()); err != nil { 44 log.Fatalf("Disconnect error: %v", err) 45 } 46 }() 47 48 collection := client.Database("test").Collection("coll") 49 if err := collection.Drop(context.TODO()); err != nil { 50 log.Fatalf("Collection.Drop error: %v", err) 51 } 52 53 if _, err = collection.InsertOne(context.TODO(), bson.D{{"encryptedField", "123456789"}}); err != nil { 54 log.Fatalf("InsertOne error: %v", err) 55 } 56 res, err := collection.FindOne(context.TODO(), bson.D{}).DecodeBytes() 57 if err != nil { 58 log.Fatalf("FindOne error: %v", err) 59 } 60 fmt.Println(res) 61} 62 63func Example_clientSideEncryptionCreateKey() { 64 keyVaultNamespace := "admin.datakeys" 65 uri := "mongodb://localhost:27017" 66 // kmsProviders would have to be populated with the correct KMS provider information before it's used 67 var kmsProviders map[string]map[string]interface{} 68 69 // Create Client and ClientEncryption 70 clientEncryptionOpts := options.ClientEncryption(). 71 SetKeyVaultNamespace(keyVaultNamespace). 72 SetKmsProviders(kmsProviders) 73 keyVaultClient, err := Connect(context.TODO(), options.Client().ApplyURI(uri)) 74 if err != nil { 75 log.Fatalf("Connect error for keyVaultClient: %v", err) 76 } 77 clientEnc, err := NewClientEncryption(keyVaultClient, clientEncryptionOpts) 78 if err != nil { 79 log.Fatalf("NewClientEncryption error: %v", err) 80 } 81 defer func() { 82 // this will disconnect the keyVaultClient as well 83 if err = clientEnc.Close(context.TODO()); err != nil { 84 log.Fatalf("Close error: %v", err) 85 } 86 }() 87 88 // Create a new data key and encode it as base64 89 dataKeyID, err := clientEnc.CreateDataKey(context.TODO(), "local") 90 if err != nil { 91 log.Fatalf("CreateDataKey error: %v", err) 92 } 93 dataKeyBase64 := base64.StdEncoding.EncodeToString(dataKeyID.Data) 94 95 // Create a JSON schema using the new data key. This schema could also be written in a separate file and read in 96 // using I/O functions. 97 schema := `{ 98 "properties": { 99 "encryptedField": { 100 "encrypt": { 101 "keyId": [{ 102 "$binary": { 103 "base64": "%s", 104 "subType": "04" 105 } 106 }], 107 "bsonType": "string", 108 "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" 109 } 110 } 111 }, 112 "bsonType": "object" 113 }` 114 schema = fmt.Sprintf(schema, dataKeyBase64) 115 var schemaDoc bson.Raw 116 if err = bson.UnmarshalExtJSON([]byte(schema), true, &schemaDoc); err != nil { 117 log.Fatalf("UnmarshalExtJSON error: %v", err) 118 } 119 120 // Configure a Client with auto encryption using the new schema 121 dbName := "test" 122 collName := "coll" 123 schemaMap := map[string]interface{}{ 124 dbName + "." + collName: schemaDoc, 125 } 126 autoEncryptionOpts := options.AutoEncryption(). 127 SetKmsProviders(kmsProviders). 128 SetKeyVaultNamespace(keyVaultNamespace). 129 SetSchemaMap(schemaMap) 130 client, err := Connect(context.TODO(), options.Client().ApplyURI(uri).SetAutoEncryptionOptions(autoEncryptionOpts)) 131 if err != nil { 132 log.Fatalf("Connect error for encrypted client: %v", err) 133 } 134 135 // Use client for operations. 136 137 if err = client.Disconnect(context.TODO()); err != nil { 138 log.Fatalf("Disconnect error: %v", err) 139 } 140} 141