Client Side Field Level Encryption, having trouble connecting to secureClient

trying to implement client side field level encryption with free mongodb atlas cluster, completed the part of generating data key id.
Then while trying to do insert encrypted doc facing problem, the code is working till connecting to reg client and after that having trouble to connect to secureClient

question 1 : do we need to install mongocryptd for atlas as well
question 2: am doing something wrong with extraOptions what should be value to the field
mongocryptdSpawnPath in extraOptions for atlas cluster

if am doing wrong anything please correct me

Thank you

code:

const mongodb = require("mongodb");
const { ClientEncryption } = require("mongodb-client-encryption");
const { MongoClient, Binary } = mongodb;
const { join } = require('path');
require('dotenv').config();

// const { getCredentials } = require("./your_credentials");
// credentials = getCredentials();

var db = "medicalRecords";
var coll = "patients";
var namespace = `${db}.${coll}`;
// start-kmsproviders
const {readFileSync} = require("fs");
const provider = "local";
const path = join(__dirname,"./master-key.txt")
const localMasterKey = readFileSync(path);
console.log(localMasterKey)
const kmsProviders = {
  local: {
    key: localMasterKey,
  },
};
// end-kmsproviders

const connectionString = process.env.URI;

// start-key-vault
const keyVaultNamespace = "encryption.__keyVault";
// end-key-vault

// start-schema
const schema = {
  bsonType: "object",
  encryptMetadata: {
    // keyId: {
    //     $binary:{
    //         base64: "PadTrVggQL+MaHprhtzdcA==",
    //         subType: "04",
    //     }
    // },
    keyId: [ new Binary(Buffer.from("PadTrVggQL+MaHprhtzdcA==", "base64"),4)],
  },
  properties: {
    insurance: {
      bsonType: "object",
      properties: {
        policyNumber: {
          encrypt: {
            bsonType: "int",
            algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
          },
        },
      },
    },
    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-Random",
      },
    },
  },
};

var patientSchema = {};
patientSchema[namespace] = schema;
// end-schema

// start-extra-options
const extraOptions = {
  // mongocryptdSpawnPath: '.'
  mongocryptdBypassSpawn: true,
};
// end-extra-options

// start-client - 

const secureClient = new MongoClient(connectionString, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
  autoEncryption: {
    keyVaultNamespace,
    kmsProviders,
    schemaMap: patientSchema,
    extraOptions: extraOptions,
  },
});
// end-client
const regularClient = new MongoClient(connectionString, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});
async function main() {
    console.log("inside main");
  try {
    //await regularClient.connect();
    console.log('reg client')
    try {
      await secureClient.connect();
      console.log('sec client')
      // start-insert
      try {
        const writeResult = await secureClient
          .db(db)
          .collection(coll)
          .insertOne({
            name: "Jon Doe",
            ssn: 241014209,
            bloodType: "AB+",
            "key-id": "demo-data-key",
            medicalRecords: [{ weight: 180, bloodPressure: "120/80" }],
            insurance: {
              policyNumber: 123142,
              provider: "MaestCare",
            },
          });
      } catch (writeError) {
        console.error("writeError occurred:", writeError);
      }
      // end-insert
      // start-find
      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, searching on an encrypted field"
      );
      console.log(
        await secureClient.db(db).collection(coll).findOne({ name: /Jon/ })
      );
      // end-find
    } catch(err) {
        console.log("secure",err);
    }
    finally {
      await secureClient.close();
    }
  } finally {
    await regularClient.close();
  }
}
main();

Error:

MongoServerSelectionError: connect ECONNREFUSED 127.0.0.1:27020
    at Timeout._onTimeout (D:\Node js\MongoDB_encryption\node_modules\mongodb\lib\sdam\topology.js:277:38)
    at listOnTimeout (internal/timers.js:557:17)
    at processTimers (internal/timers.js:500:7) {
  reason: TopologyDescription {
    type: 'Unknown',
    servers: Map(1) { 'localhost:27020' => [ServerDescription] },
    stale: false,
    compatible: true,
    heartbeatFrequencyMS: 10000,
    localThresholdMS: 15,
    setName: null,
    maxElectionId: null,
    maxSetVersion: null,
    commonWireVersion: 0,
    logicalSessionTimeoutMinutes: null
  },
  code: undefined,
  [Symbol(errorLabels)]: Set(0) {}
}
1 Like

Hello. The “connect ECONNREFUSED 127.0.0.1:27020” indicates the Node code was attempting to perform automatic encryption, but could not locate either the mongocryptd or shared_crypt libraries (you only need one, and both packages are available from the Enterprise Downloads page (MongoDB Enterprise Server Download | MongoDB); note you only need the cryptd or crypt_shared package, not the entire server. Both libraries are fully licensed for all Atlas users (including the free tiers) and Enterprise, but one or the other need to be specifically installed, they won’t get pulled down automatically with your language dependencies like libmongocrypt will.

Hope that helps!

-Kenn

2 Likes

Hi Kennth_White,

I have downloaded the crypt-shared package for the above example. Can you please guide me on what particular file in that package I need to specify in my code?

Hi Rajat.

For crypt_shared, you need to either put the mongo_crypt_v1.so (mongo_crypt_v1.dylib on Mac) on the default path, or specify it explicitly on the extraOptions cryptSharedLibPath, e.g.:

ExtraOptions: {
      cryptSharedLibPath: "/home/appUser/node/mongo_crypt_v1.so"
}

Alternatively, if you choose to use the mongocryptd package, then you can just run that on bootup/container start, or launch into a detached background process, e.g.:
$ ( ./mongocryptd 2>&1 >> /var/log/mongocryptd.log &)

See https://www.mongodb.com/docs/manual/core/csfle/reference/mongocryptd/ and
https://www.mongodb.com/docs/manual/core/queryable-encryption/reference/shared-library/#configuration.

There’s a full code example with switchable language snippets for setting crypt_shared here: https://www.mongodb.com/docs/manual/core/queryable-encryption/quick-start/#create-your-encrypted-collection

Cheers.
Kenn

1 Like

And here’s the full repo for Node that’s referenced in the Quick Start (I’ve highlighted the crypt_shared part, but take a look at the whole ./node/local/reader folder in the repo) here: docs-in-use-encryption-examples/insert_encrypted_document.js at main · mongodb-university/docs-in-use-encryption-examples · GitHub

Hi, thanks for guide on this, after setting up locally, how we can setup in docker for cloud deployments on render

here is my current docker file, followed through most installation guides, yet still having issues installing mongo_client_encryption 

FROM node:15-alpine3.11

WORKDIR /usr/src/app

RUN apk update && apk add --no-cache nmap && \
    echo @edge https://dl-cdn.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \
    echo @edge https://dl-cdn.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \
    apk update && \
    apk add --no-cache \
    python3 \
    py3-pip \
    py3-packaging \
    py3-setuptools \
    make \
    g++ \
    gcc \
    git \
    cmake \
    openssl-dev \
    linux-headers \
    chromium \
    harfbuzz \
    "freetype>2.8" \
    ttf-freefont \
    nss \
    bash \
    wget \
    curl \
    libgcc \
    libstdc++ \
    ca-certificates \
    libcurl 

# Build and install libmongocrypt
RUN git clone https://github.com/mongodb/libmongocrypt.git && \
    cd libmongocrypt && \
    cmake -DENABLE_SHARED_BSON=ON \
         -DCMAKE_INSTALL_PREFIX=/usr/local \
         -DBUILD_VERSION=1.7.3 . && \
    make && \
    make install && \
    cd .. && \
    rm -rf libmongocrypt

# Set environment variables
ENV PYTHON=/usr/bin/python3
ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH


RUN curl -L -o mongo_crypt_shared.tgz \
    https://github.com/Talesconnect/mongo_tools/raw/main/mongo_crypt_shared_v1-linux-x86_64-enterprise-ubuntu2004-8.0.4.tgz && \
    tar -xvf mongo_crypt_shared.tgz && \
    mkdir -p /usr/local/lib && \
    mv lib/mongo_crypt_v1.so /usr/local/lib/mongo_crypt_v1.so && \
    rm mongo_crypt_shared.tgz
    
# Set the library path
ENV CSFLE_CRYPT_SHARED_LIB_PATH=/usr/local/lib/mongo_crypt_v1.so
ENV MONGODB_CRYPT_SHARED_LIB_PATH=/usr/local/lib/mongo_crypt_v1.so
ENV MONGOCRYPT_LIB_DIR=/usr/local/lib
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

# Copy package.json and yarn.lock to install dependencies
COPY package*.json ./
RUN yarn global add rimraf && \
    yarn install

# Copy application code
COPY . .

RUN yarn build

CMD ["node", "--optimize_for_size", "--max_old_space_size=460", "--gc_interval=100", "dist/main.js"]