Bearer token as db password

I am looking for help here. I got a django project wherein I need to use dynamically generated bearer token as password for database. I am using postgres on GCP CloudSQL.

I have tried using a function within and outside file but the issue is the settings file is read only once while building the project. Hence the function gets call only one time when runserver is executed.
Tried using env variables as well but that too fails given the same constraints with one time reading of settings file.

Details: I am trying to generate token using ‘gcloud auth print-access-token’ which perfectly provides me with a valid token. But it helps me with connection only first time since connection object doesn’t refer to file everytime it needs to connect. I am closing connection after every single operation, just in case you need to know.

Any help on this is really appreciated. TIA.

Could you store it to a .env file then use a dotenv library to load it to environment variables?

You’d still have to deal with restarting all your django processes after updating the env file.

.env file can be used for string values only, if I am not mistaken. I am looking for a function’s output to be used as db password. This output will change approx. every 35 mins

I’m confused, how does that eliminate storing the connection info in a .env file from a possibility?

Keep in mind, you can write a script that manipulates the results of gcloud auth print-access-token into whatever form you need then the script runs runserver at the end.

But every time I get the updated token every 30 minutes and if I run runserver command, would it not stop the application usage in between ?

We wish to have users continue using their application while the barrel token get updated in connection string. Database operations are very minimal and usually are not required for about 20% of total application usage

I think your best bet here would be to create a custom database engine that calls a function to get the current password instead of reading it from the settings file. Otherwise, I think you’re likely to encounter issues with middleware and possibly non-request-related database access.

Note, with authenticated users, 100% of your requests are going to use the database.

1 Like

Any help or sample code to achieve this would be really helpful :pray:t2:

I’ve never had to do this, so I’m just tossing out some thoughts and ideas here. I don’t have any actual code to share.

Lessee… First, you’ll need some sort of mechanism to get the current password and put it in a location that every Django process will be able to access.

If I were doing something like this, I’d be using redis - but that’s primarily because I rely upon redis in most of my systems for doing a variety of things. This means that I’m already familiar with it and I know it’s going to be available in my environments. However, redis definitely isn’t required. You could use memcached - or even just writing it out to a file. Whatever you feel comfortable with.

Then, I would create a stand-alone process that does whatever needed to be done to create/retrieve that password and store it in the appropriate location.

Finally, I’d create the database engine to retrieve that password from that location whenever a connection is going to be made. It looks like the function that you would want to replace is the get_new_connection method in django.db.backends.postgresql.base.DatabaseWrapper.

You could probably copy the entire postgresql backend into your project and modify it directly - or you could possibly just create the files you need and import the code you need from the parent classes. (I did something like this for a different purpose - see Database instrumentation at a higher layer for some ideas.)

1 Like