Last active
March 23, 2022 13:01
-
-
Save kennwhite/c1b598f8433ee1e662b55a06dc69161a to your computer and use it in GitHub Desktop.
Simple MongoDB client-side field level encryption (libmongocrypt) demo on Alpine Linux with .NET
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# WARNING: This is a demonstration only, not any kind of official build - use at your own risk | |
# Launched standard Alpine Linux AMI on an t2.micro instance configured w/ 8GB: | |
# alpine-3.15.1-x86_64-bios-cloudinit-r0 - ami-0421638898b821bff | |
# | |
# ssh -i mykey.pem alpine@[instance address] | |
# This demo runs as default non-root "alpine" user | |
cd /home/alpine | |
# .NET installer dependencies | |
sudo apk add bash icu-dev | |
wget https://dot.net/v1/dotnet-install.sh | |
# Installed via MS .NET docs https://docs.microsoft.com/en-us/dotnet/core/install/linux-scripted-manual#scripted-install | |
# defaults to current LTS version (6) | |
chmod +x ./dotnet-install.sh | |
./dotnet-install.sh | |
# Add .NET tools & locally-built libraries | |
export PATH=$PATH:/home/alpine/.dotnet:/usr/local/lib | |
# Sanity check | |
dotnet --info | |
uname -a | |
cat /etc/os-release | |
sudo apk add git make cmake g++ libbson-static musl-dev libc-dev openssl openssl-dev py3-pip | |
git clone https://github.com/mongodb/mongo-c-driver | |
cd /home/alpine/mongo-c-driver/ | |
cmake -DENABLE_MONGOC=OFF . | |
# Note: warning issued for: Policy CMP0075 is not set: Include file check macros honor | |
sudo make -j8 install | |
cd /home/alpine | |
git clone https://github.com/mongodb/libmongocrypt | |
cd /home/alpine/libmongocrypt | |
cmake . | |
# Throws similar warning: CMake Warning at CMakeLists.txt:416 (find_package): | |
# By not providing "Findmongoc-1.0.cmake" in CMAKE_MODULE_PATH this project | |
# has asked CMake to find a package configuration file provided by | |
# "mongoc-1.0", but CMake did not find one. | |
sudo make install | |
mkdir /home/alpine/app | |
cd /home/alpine/app | |
cat << EOF > app.csproj | |
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net6.0</TargetFramework> | |
<ImplicitUsings>enable</ImplicitUsings> | |
<Nullable>enable</Nullable> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="MongoDB.Bson" Version="2.15.0" /> | |
<PackageReference Include="MongoDB.Driver" Version="2.15.0" /> | |
<PackageReference Include="MongoDB.Driver.Core" Version="2.15.0" /> | |
</ItemGroup> | |
</Project> | |
EOF | |
# cat app.csproj | |
cat << EOF > app.cs | |
[contents of https://mongodb.github.io/mongo-csharp-driver/2.15/reference/driver/crud/client_side_encryption/#explicit-encryption-and-auto-decryption] | |
EOF | |
# NOTE: Change the 2 localhost references in app.cs to a real connection string, e.g: | |
# var keyVaultClient = new MongoClient("mongodb+srv://appuser:XXXX@cluster0.xxx.mongodb.net/test?retryWrites=true&w=majority"); | |
cd /home/alpine/app | |
dotnet publish -c release -o publish -r linux-musl-x64 --self-contained | |
cp /usr/local/lib/libmongocrypt.so ./bin/release/net6.0/linux-musl-x64/ | |
cp /usr/local/lib/libmongocrypt.so ./publish/ | |
# Confirm this instance's IP has network permissions to the database | |
wget -qO- icanhazip.com | |
# Alternatively: ./publish/app | |
./bin/release/net6.0/linux-musl-x64/app | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ dotnet --info | |
.NET SDK (reflecting any global.json): | |
Version: 6.0.103 | |
Commit: 2d7bc7059f | |
Runtime Environment: | |
OS Name: alpine | |
OS Version: 3.15 | |
OS Platform: Linux | |
RID: alpine.3.15-x64 | |
Base Path: /home/alpine/.dotnet/sdk/6.0.103/ | |
Host (useful for support): | |
Version: 6.0.3 | |
Commit: c24d9a9c91 | |
.NET SDKs installed: | |
6.0.103 [/home/alpine/.dotnet/sdk] | |
.NET runtimes installed: | |
Microsoft.AspNetCore.App 6.0.3 [/home/alpine/.dotnet/shared/Microsoft.AspNetCore.App] | |
Microsoft.NETCore.App 6.0.3 [/home/alpine/.dotnet/shared/Microsoft.NETCore.App] | |
To install additional .NET runtimes or SDKs: | |
https://aka.ms/dotnet-download | |
$ uname -a | |
Linux ip-172-30-0-227 5.15.29-0-virt #1-Alpine SMP Wed, 16 Mar 2022 15:02:59 +0000 x86_64 Linux | |
$ cat /etc/os-release | |
NAME="Alpine Linux" | |
ID=alpine | |
VERSION_ID=3.15.1 | |
PRETTY_NAME="Alpine Linux v3.15" | |
HOME_URL="https://alpinelinux.org/" | |
BUG_REPORT_URL="https://bugs.alpinelinux.org/" | |
$ ./bin/release/net6.0/linux-musl-x64/app | |
Original string 123456789. | |
Encrypted value Encrypted:0x013ee87f33fc384c6ea50ed6c1a7090eb002f2129159c32ed7890935f1fea69f6ddfd82b798b927bb885e2f3a1ee21f8e2fd4507433c39c57085f711812c9ba3332065a68d52894c6dcb7567e528d5d7a8b5. | |
Decrypted document { "_id" : ObjectId("623a9901331480269e996fc6"), "encryptedField" : "123456789" }. | |
$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// From: https://mongodb.github.io/mongo-csharp-driver/2.15/reference/driver/crud/client_side_encryption/#explicit-encryption-and-auto-decryption | |
// NOTE: You MUST update the 2 connection strings "xxxx" for your database | |
using System; | |
using System.Collections.Generic; | |
using System.Threading; | |
using MongoDB.Bson; | |
using MongoDB.Driver.Encryption; | |
using MongoDB.Libmongocrypt; | |
namespace MongoDB.Driver.Examples | |
{ | |
public class ExplicitEncryptionAndAutoDecryptionExamples | |
{ | |
private const string LocalMasterKey = "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk"; | |
public static void Main(string[] args) | |
{ | |
var localMasterKey = Convert.FromBase64String(LocalMasterKey); | |
var kmsProviders = new Dictionary<string, IReadOnlyDictionary<string, object>>(); | |
var localKey = new Dictionary<string, object> | |
{ | |
{ "key", localMasterKey } | |
}; | |
kmsProviders.Add("local", localKey); | |
var keyVaultNamespace = CollectionNamespace.FromFullName("keyvault.datakeys"); | |
var collectionNamespace = CollectionNamespace.FromFullName("test.coll"); | |
var autoEncryptionOptions = new AutoEncryptionOptions( | |
keyVaultNamespace, | |
kmsProviders, | |
bypassAutoEncryption: true); | |
var clientSettings = MongoClientSettings.FromConnectionString("mongodb+srv://appuser:XXXX@cluster0.xxxxx.mongodb.net/test?retryWrites=true&w=majority"); | |
clientSettings.AutoEncryptionOptions = autoEncryptionOptions; | |
var mongoClient = new MongoClient(clientSettings); | |
var database = mongoClient.GetDatabase(collectionNamespace.DatabaseNamespace.DatabaseName); | |
database.DropCollection(collectionNamespace.CollectionName); | |
var collection = database.GetCollection<BsonDocument>(collectionNamespace.CollectionName); | |
var keyVaultClient = new MongoClient("mongodb+srv://appuser:XXXX@cluster0.xxxxx.mongodb.net/test?retryWrites=true&w=majority"); | |
var keyVaultDatabase = keyVaultClient.GetDatabase(keyVaultNamespace.DatabaseNamespace.DatabaseName); | |
keyVaultDatabase.DropCollection(keyVaultNamespace.CollectionName); | |
// Create the ClientEncryption instance | |
var clientEncryptionSettings = new ClientEncryptionOptions( | |
keyVaultClient, | |
keyVaultNamespace, | |
kmsProviders); | |
using (var clientEncryption = new ClientEncryption(clientEncryptionSettings)) | |
{ | |
var dataKeyId = clientEncryption.CreateDataKey( | |
"local", | |
new DataKeyOptions(), | |
CancellationToken.None); | |
var originalString = "123456789"; | |
Console.WriteLine($"Original string {originalString}."); | |
// Explicitly encrypt a field | |
var encryptOptions = new EncryptOptions( | |
EncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic.ToString(), | |
keyId: dataKeyId); | |
var encryptedFieldValue = clientEncryption.Encrypt( | |
originalString, | |
encryptOptions, | |
CancellationToken.None); | |
Console.WriteLine($"Encrypted value {encryptedFieldValue}."); | |
collection.InsertOne(new BsonDocument("encryptedField", encryptedFieldValue)); | |
// Automatically decrypts the encrypted field. | |
var decryptedValue = collection.Find(FilterDefinition<BsonDocument>.Empty).First(); | |
Console.WriteLine($"Decrypted document {decryptedValue.ToJson()}."); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment