Securing passwords using PyMongo during client connection

Hi there! I’m using pymongo for connecting to my cluster. I’m developing this for an open source project, how do I connect to the client since the pymongo MongoClient requires your credentials to proceed.

MongoClient Docs

I don’t want to store that secret key in my code since it is to be distributed, so how can I connect to my cluster using any other technique?

The most common pattern to avoid storing the password in the application code is to put the entire connection string (or URI) in an environment variable like this:

$ export APP_URI='mongodb://user:pass@mongodb.net/?tls=true'
$ python3
>>> import os
>>> client = MongoClient(os.environ['APP_URI'])
>>> client.admin.command('ping')
{'ok': 1}

I’d like to point out that one other way of doing this would be to only store the secret password in an environment variable and then use the username, password parameters of the MongoClient constructor to connect to the cluster. Note however, that this method is PyMongo-specific as not all drivers would expose similar parameters for specifying usernames/passwords.

$ export APP_PASSWORD='mypassword123'
$ python3
>>> import os
>>> client = MongoClient('mongodb://mongodb.net/?tls=true', username='user', password=os.environ['APP_PASSWORD'])
>>> client.admin.command('ping')
{'ok': 1}

Hi Prashant! I want my app to be usable by others too. Since the password is stored in the environment variable, d during compilation, if I don’t include the .env, the app will not be able to connect to a cluster.

How do I overcome this problem? Thanks in advance!

Hi Shane! Thanks for helping!

Just one more thing, how do I deploy applications to desktop because I need to access the APP_URI, and for using it, the executable needs to access the environment variable which is not stored client’s side.

The environment variable is secret and stored in .env files, and during compilation if I don’t include the .env, the app will not be able to connect to a database.

I hope you get my problem. Thanks in advance!

I think the solution to your problem depends on how you are deploying your app. Most deployment tools provide some API to define encrypted secrets that can be used at runtime (in this case as an environment variable).

For instance, if you are using ansible to deploy the app on the target machine, you can use ansible-vault (https://docs.ansible.com/ansible/latest/user_guide/vault.html) to encrypt the secrets which can then be used in your ansible playbooks to export the appropriate environment variable.

I am trying to deploy my app using PyInstaller. The code is converted to a binary executable, so I don’t think anything can be done with an API. The credentials still need to go through the API.

I might be wrong with my interpretation, but can you please help me further?

In the case of applications that are distributed as an executable (as opposed to being deployed to a webserver which serves requests issued by the end-user), the closest analogue to secrets is probably a software license. What I mean here by a license is any additional file without which, the executable either cannot run or can only run with restricted functionality (e.g. ‘Trial mode’). In your case, the license can be an encrypted file which the main executable knows how to decrypt and expects to find at a fixed location on the filesystem (or relative to its own location). The ‘license’ file can contain the connection string secret.

Please keep in mind that I am only offering ideas based on what I think you are trying to achieve. The correct answer will need to be informed most closely by your intended use-case.