Integrar o Azure Key Vault com a criptografia em nível de campo no lado do cliente do MongoDB
Avalie esse Tutorial
Ao implementar a criptografia em nível de campodo MongoDBno lado do cliente (CSFLE), você se verá fazendo uma decisão importante: onde armazeno minha chave mestra do cliente? Em outro tutorial, oriento os leitores sobre os fundamentos do CSFLE usando uma chave mestra gerada e armazenada localmente. Embora isso funcione para fins informativos e de desenvolvimento local, não é adequado para produção! Neste tutorial, vamos ver como usar o Azure Key Vault para gerar e armazenar com segurança nossa chave mestra.
- Um cluster do MongoDB Atlas executando o MongoDB 4.2 (ou posterior) OU MongoDB 4.2 Enterprise Server (ou posterior) — necessário para criptografia automática
- Driver MongoDB .NET 2.13.0 (ou posterior)
- Uma Conta Azure com uma assinatura ativa e as mesmas permissões que as encontradas em qualquer uma dessas roles do Azure AD (somente uma é necessária):
Prepare a infraestrutura do Azure
Configure seu aplicativo cliente para usar o Azure Key Vault e o CSFLE
Para estabelecer uma relação de confiança entre nosso aplicativo e a plataforma de identidade da Microsoft, primeiro precisamos registrá-lo.
- Se você tiver acesso a vários inquilinos, no menu superior, use o “Directory + subscription filter” para selecionar o inquilino no qual você deseja registrar um aplicativo.
- Na barra de pesquisa principal, pesquise e selecione “Azure Active Directory.”
- No menu de navegação à esquerda, encontre a seção Gerenciar e selecione "App registrations," e depois "+ New registration."
- Insira um nome de exibição para seu aplicativo. Você pode alterar o nome de exibição a qualquer momento e vários registros de aplicativos podem compartilhar o mesmo nome. O ID do aplicativo (cliente) gerado automaticamente pelo registro do aplicativo, não seu nome de exibição, identifica seu aplicativo de forma exclusiva na plataforma de identidade.
- Especifique quem pode usar o aplicativo, às vezes chamado de público-alvo de login. Para este tutorial, selecionei "Accounts in this organizational directory only (Default Directory only - Single tenant)." Isso só permite que os usuários que estão no meu locatário atual acessem meu aplicativo.
- Clique em “Register.” Assim que o registro inicial do aplicativo for concluído, copie o ID do diretório (locatário) e o ID do aplicativo (cliente), pois precisaremos deles mais tarde.
- Encontre o aplicativo vinculado em "Managed application in local directory " e clique nele.
- Uma vez levado para a página “Properties”, copie também o “Object ID”, pois precisaremos dele também.
Depois que seu aplicativo for registrado, precisaremos criar um segredo do cliente para ele. Isso será necessário ao autenticar no Key Vault que criaremos em breve.
- Na visão geral do seu aplicativo recém-registrado, clique em “Add a certificate or secret”:
- Em “Client secrets,”, clique em “+ New client secret.”
- Insira uma breve descrição para este segredo do cliente e deixe a configuração padrão "Expires " de 6 meses.
- Clique em "Ad." Once the client secret is created, be sure to copy the secret’s “Value", pois precisaremos dele mais tarde. Também vale a pena mencionar que, depois de sair desta página, o valor secreto nunca mais será exibido, portanto, certifique-se de registrá-lo pelo menos uma vez!
Em seguida, um Azure Key Vault! Criaremos uma para que possamos armazenar com segurança a chave mestra do cliente. Estaremos concluindo estas etapas por meio da CLI do Azure, então abra seu terminal favorito e acompanhe:
- Entre no Azure CLI utilizando o comando
az login
. Conclua as etapas de autenticação seguindo as etapas exibidas no seu terminal. - Crie um grupo de recursos:
1 az group create --name "YOUR-RESOURCE-GROUP-NAME" --location <YOUR-AZURE-REGION> - Crie um cofre de chaves:
1 az keyvault create --name "YOUR-KEYVAULT-NAME" --resource-group "YOUR-RESOURCE-GROUP-NAME" --location <YOUR-AZURE-REGION>
Com um cofre de chaves, agora podemos criar nossa chave mestra do cliente! Isso será armazenado, gerenciado e protegido pelo Azure Key Vault.
Criar uma chave e adicionar ao nosso cofre de chaves:
1 az keyvault key create --vault-name "YOUR-KEYVAULT-NAME" --name "YOUR-KEY-NAME" --protection software
O parâmetro
--protection
designa otipo de proteção de chave. Por enquanto, usaremos o tiposoftware
. Quando o comando for concluído, anote o "nome" da sua chave, pois precisaremos dela mais tarde!Para habilitar o acesso do aplicativo do cliente ao cofre de chaves, algumas permissões precisam ser concedidas:
- Dê ao seu aplicativo as permissõeswrapKey e unwrapKey para o keyvault. (Para o parâmetro
--object-id
, cole o ID do objeto do aplicativo que registramos anteriormente. Esse é o ID do objeto que copiamos na última etapa "Registrar aplicativo no Azure Active Directory".)1 az keyvault set-policy --name "YOUR-KEYVAULT-NAME" --key-permissions wrapKey unwrapKey --object-id <YOUR-APP-OBJECT-ID> - Após o sucesso, você receberá um objeto JSON. Encontre e copie o valor da chave "vaultUri ". Por exemplo, o meu é
https://csfle-mdb-demo-vault.vault.azure.net
.
Agora que nossa infraestrutura em nuvem está configurada, podemos começar a integrá-la ao nosso aplicativo. Faremos referência ao repositório de amostraa partir de nossos pré-requisitos para essas etapas, mas fique à vontade para usar as partes necessárias em um aplicativoexistente.
- Se você ainda não clonou o repositório, faça isso agora!
1 git clone https://github.com/adriennetacke/mongodb-csfle-csharp-demo-azure.git - Navegue até o diretório raiz
mongodb-csfle-csharp-demo-azure
e abra o aplicativo de amostraEnvoyMedSys
no Visual Studio. - No Solution Explorer, localize e abra o arquivo
launchSettings.json
(Properties
>launchSettings.json
). - Aqui, você verá alguns andaimes para algumas variáveis. Vamos Go rapidamente o que são:
MDB_ATLAS_URI
A string de conexão para o seu cluster do MongoDB Atlas. Isso nos permite armazenar nossa chave de encriptação de dados, criptografada pelo Azure Key Vault.AZURE_TENANT_ID
Identifica a organização da conta do Azure.AZURE_CLIENT_ID
: Identifica oclientId
para autenticar seu aplicativo registrado.AZURE_CLIENT_SECRET
Usado para autenticar seu aplicativo registrado.AZURE_KEY_NAME
Nome da Chave Mestra do Cliente armazenada no Azure Key Vault.AZURE_KEYVAULT_ENDPOINT
: URL do Key Vault. Por exemplo,yourVaultName.vault.azure.net
.
- Substitua todos os espaços reservados no arquivo
launchSettings.json
porsuas próprias informações. Cada variável corresponde a um valor que você foi solicitado para copiar e acompanhar:AZURE_TENANT_ID
: ID do diretório (locatário).AZURE_CLIENT_ID
: ID do aplicativo (cliente).AZURE_CLIENT_SECRET
:valorsecreto do segredo do cliente.AZURE_KEY_NAME
:Nomeda Chave.AZURE_KEYVAULT_ENDPOINT
: vaultUrido nosso Key Vault.
- Salve todos os seus arquivos!
Antes de executarmos o aplicativo, vamos analisar o que está acontecendo: quando executamos nosso programa principal, definimos a conexão com o cluster Atlas e o namespace da collection do cofre de chaves. Em seguida, instanciamos duas classes auxiliares:
KmsKeyHelper
e AutoEncryptHelper
. O KmsKeyHelper
CreateKeyWithAzureKmsProvider()
método do é chamado para gerar nossa chave de criptografia de dados criptografados. Em seguida, isso é passado para o AutoEncryptHelper
EncryptedWriteAndReadAsync()
método do para inserir um documento de amostra com campos criptografados e descriptografá-lo adequadamente quando precisarmos buscá-lo. Tudo isso está em nosso Program.cs
arquivo :Program.cs
1 using System; 2 using MongoDB.Driver; 3 4 namespace EnvoyMedSys 5 { 6 public enum KmsKeyLocation 7 { 8 Azure, 9 } 10 11 class Program 12 { 13 public static void Main(string[] args) 14 { 15 var connectionString = Environment.GetEnvironmentVariable("MDB_ATLAS_URI"); 16 var keyVaultNamespace = CollectionNamespace.FromFullName("encryption.__keyVaultTemp"); 17 18 var kmsKeyHelper = new KmsKeyHelper( 19 connectionString: connectionString, 20 keyVaultNamespace: keyVaultNamespace); 21 var autoEncryptHelper = new AutoEncryptHelper( 22 connectionString: connectionString, 23 keyVaultNamespace: keyVaultNamespace); 24 25 var kmsKeyIdBase64 = kmsKeyHelper.CreateKeyWithAzureKmsProvider().GetAwaiter().GetResult(); 26 27 autoEncryptHelper.EncryptedWriteAndReadAsync(kmsKeyIdBase64, KmsKeyLocation.Azure).GetAwaiter().GetResult(); 28 29 Console.ReadKey(); 30 } 31 } 32 }
Dando uma olhada na classe
KmsKeyHelper
, há alguns métodos importantes: os métodos CreateKeyWithAzureKmsProvider()
e GetClientEncryption()
. Optou por incluir comentários no código para facilitar o acompanhamento: KmsKeyHelper.cs
/ CreateKeyWithAzureKmsProvider()
1 public async Task<string> CreateKeyWithAzureKmsProvider() 2 { 3 var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>(); 4 5 // Pull Azure Key Vault settings from environment variables 6 var azureTenantId = Environment.GetEnvironmentVariable("AZURE_TENANT_ID"); 7 var azureClientId = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID"); 8 var azureClientSecret = Environment.GetEnvironmentVariable("AZURE_CLIENT_SECRET"); 9 var azureIdentityPlatformEndpoint = Environment.GetEnvironmentVariable("AZURE_IDENTIFY_PLATFORM_ENPDOINT"); // Optional, only needed if user is using a non-commercial Azure instance 10 11 // Configure our registered application settings 12 var azureKmsOptions = new Dictionary<string, object> 13 { 14 { "tenantId", azureTenantId }, 15 { "clientId", azureClientId }, 16 { "clientSecret", azureClientSecret }, 17 }; 18 19 if (azureIdentityPlatformEndpoint != null) 20 { 21 azureKmsOptions.Add("identityPlatformEndpoint", azureIdentityPlatformEndpoint); 22 } 23 24 // Specify remote key location; in this case, Azure 25 kmsProviders.Add("azure", azureKmsOptions); 26 27 // Constructs our client encryption settings which 28 // specify which key vault client, key vault namespace, 29 // and KMS providers to use. 30 var clientEncryption = GetClientEncryption(kmsProviders); 31 32 // Set KMS Provider Settings 33 // Client uses these settings to discover the master key 34 var azureKeyName = Environment.GetEnvironmentVariable("AZURE_KEY_NAME"); 35 var azureKeyVaultEndpoint = Environment.GetEnvironmentVariable("AZURE_KEYVAULT_ENDPOINT"); // typically <azureKeyName>.vault.azure.net 36 var azureKeyVersion = Environment.GetEnvironmentVariable("AZURE_KEY_VERSION"); // Optional 37 var dataKeyOptions = new DataKeyOptions( 38 masterKey: new BsonDocument 39 { 40 { "keyName", azureKeyName }, 41 { "keyVaultEndpoint", azureKeyVaultEndpoint }, 42 { "keyVersion", () => azureKeyVersion, azureKeyVersion != null } 43 }); 44 45 // Create Data Encryption Key 46 var dataKeyId = clientEncryption.CreateDataKey("azure", dataKeyOptions, CancellationToken.None); 47 Console.WriteLine($"Azure DataKeyId [UUID]: {dataKeyId}"); 48 49 var dataKeyIdBase64 = Convert.ToBase64String(GuidConverter.ToBytes(dataKeyId, GuidRepresentation.Standard)); 50 Console.WriteLine($"Azure DataKeyId [base64]: {dataKeyIdBase64}"); 51 52 // Optional validation; checks that key was created successfully 53 await ValidateKeyAsync(dataKeyId); 54 55 return dataKeyIdBase64; 56 }
KmsKeyHelper.cs
/ GetClientEncryption()
1 private ClientEncryption GetClientEncryption( 2 Dictionary<string, IReadOnlyDictionary<string, object>> kmsProviders) 3 { 4 // Construct a MongoClient using our Atlas connection string 5 var keyVaultClient = new MongoClient(_mdbConnectionString); 6 7 // Set MongoClient, key vault namespace, and Azure as KMS provider 8 var clientEncryptionOptions = new ClientEncryptionOptions( 9 keyVaultClient: keyVaultClient, 10 keyVaultNamespace: _keyVaultNamespace, 11 kmsProviders: kmsProviders); 12 13 return new ClientEncryption(clientEncryptionOptions); 14 }
Com o Azure Key Vault conectado e a chave de encriptação de dados criptografada, estamos prontos para inserir alguns dados em nosso Atlas cluster! É aqui que entra a classe
AutoEncryptHelper
. O método importante a ser observado aqui é o métodoEncryptedReadAndWrite()
: AutoEncryptHelper.cs
/ EncryptedReadAndWrite()
1 public async Task EncryptedWriteAndReadAsync(string keyIdBase64, KmsKeyLocation kmsKeyLocation) 2 { 3 // Construct a JSON Schema 4 var schema = JsonSchemaCreator.CreateJsonSchema(keyIdBase64); 5 6 // Construct an auto-encrypting client 7 var autoEncryptingClient = CreateAutoEncryptingClient( 8 kmsKeyLocation, 9 _keyVaultNamespace, 10 schema); 11 12 // Set our working database and collection to medicalRecords.patientData 13 var collection = autoEncryptingClient 14 .GetDatabase(_medicalRecordsNamespace.DatabaseNamespace.DatabaseName) 15 .GetCollection<BsonDocument>(_medicalRecordsNamespace.CollectionName); 16 17 var ssnQuery = Builders<BsonDocument>.Filter.Eq("ssn", __sampleSsnValue); 18 19 // Upsert (update if found, otherwise create it) a document into the collection 20 var medicalRecordUpdateResult = await collection 21 .UpdateOneAsync(ssnQuery, new BsonDocument("$set", __sampleDocFields), new UpdateOptions() { IsUpsert = true }); 22 23 if (!medicalRecordUpdateResult.UpsertedId.IsBsonNull) 24 { 25 Console.WriteLine("Successfully upserted the sample document!"); 26 } 27 28 // Query by SSN field with auto-encrypting client 29 var result = await collection.Find(ssnQuery).SingleAsync(); 30 31 // Proper result in console should show decrypted, human-readable document 32 Console.WriteLine($"Encrypted client query by the SSN (deterministically-encrypted) field:\n {result}\n"); 33 }
Agora que sabemos o que está rolando, execute seu aplicativo!
Se tudo correr bem, seu console imprimirá dois
DataKeyIds
(UUID e64 base ) e um documento semelhante ao seguinte: Sample Result Document (using my information)
1 { 2 _id:UUID('ab382f3e-bc79-4086-8418-836a877efff3'), 3 keyMaterial:Binary('tvehP03XhUsztKr69lxlaGjiPhsNPjy6xLhNOLTpe4pYMeGjMIwvvZkzrwLRCHdaB3vqi9KKe6/P5xvjwlVHacQ1z9oFIwFbp9nk...', 0), 4 creationDate:2021-08-24T05:01:34.369+00:00, 5 updateDate:2021-08-24T05:01:34.369+00:00, 6 status:0, 7 masterKey:Object, 8 provider:"azure", 9 keyVaultEndpoint:"csfle-mdb-demo-vault.vault.azure.net", 10 keyName:"MainKey" 11 }
Veja como é a saída do meu console, para referência:
Ver isso é uma ótima notícia! Muitas coisas acabaram de acontecer, e todas elas são boas:
- Nosso aplicativo foi autenticado corretamente em nosso Azure Key Vault.
- Uma chave de criptografia de dados gerada corretamente foi criada pelo nosso aplicativo cliente.
- A chave de criptografia de dados foi criptografada corretamente pela chave mestra do cliente que está armazenada com segurança no Azure Key Vault.
- A chave de encriptação de dados criptografada foi retornada ao nosso aplicativo e armazenada em nosso MongoDB Atlas cluster.
Aqui está o mesmo processo em um fluxo de trabalho:
Depois de mais alguns instantes, e após o sucesso, você verá uma mensagem "Successfully upserted the sample document!", seguida pelos resultados devidamente descriptografados de uma consulta de teste. Novamente, aqui está a saída do meu console para referência:
Isso significa que nosso documento de amostra foi criptografado corretamente, inserido em nossa coleção
patientData
, consultado com nosso cliente de criptografia automática por SSN e teve todos os campos relevantes descriptografados corretamente antes de retorná-los ao nosso console. Que legal!E só por ser um pouco paranóia, podemos verificar se nossos dados foram realmente criptografados. Se você fizer login em seu Atlas cluster e navegar até a coleção
patientData
, verá que os campos confidenciais de nossos documentos estão todos ilegíveis:Isso não foi tão ruim, certo? Vamos ver o que conseguimos! Este tutorial mostrou a você:
- Registrando um aplicativo no Azure Active Directory.
- Criando um segredo do cliente.
- Criando um Azure Key Vault.
- Criar e adicionar uma chave ao seu Key Vault.
- Concedendo permissões de aplicativo para o Key Vault.
- Integrando o Azure Key Vault ao seu aplicativo cliente.
- Os resultados: o que você obtém após integrar o Azure Key Vault com o MongoDB CSFLE.
Ao usar um sistema de gerenciamento de chaves remoto como o Azure Key Vault, você obtém acesso a muitos benefícios em relação ao uso de um sistema de arquivos local. O mais importante deles é o armazenamento seguro da chave, risco reduzido de problemas de permissão de acesso e portabilidade mais fácil!
Para obter mais informações, confira esta lista útil de recursos que usei ao preparar este tutorial:
E se você tiver alguma dúvida ou precisar de ajuda adicional, não deixe de nos consultar nos fóruns daMongoDB Community e iniciar um tópico!
Uma comunidade inteira de engenheiros do MongoDB (incluindo a equipe DevRel) e outros desenvolvedores com certeza ajudarão!