Support SECRET_KEY and Database creds as callables

125 views
Skip to first unread message

Andres Mejia

unread,
Jan 24, 2015, 10:30:07 AM1/24/15
to django-d...@googlegroups.com
Hello Django devs,

I would like to see if Django can support setting the SECRET_KEY and
database creds as callables. Let me explain my situation.

Here at Amazon, we use a system to store and fetch secrets such as a
Django SECRET_KEY and database creds. There's a Python component to this
system which works something like this.

SECRET_KEY = get_creds(secret_key_id, type='privatekey')
. . .
DATABASES = {
'default' = {
. . .
'USER': get_creds(database_creds_id, type='username'),
'PASSWORD': get_creds(database_creds_id, type='password'),
},
. . .
}

Secrets are rotated on a regular schedule or as needed. Often times the
secrets are rotated without advance notice and therefore our various
Django powered sites go down (because they can't connect to the
database) until the web servers are restarted. We would prefer it if our
web services did not have to be restarted.

I was going to propose a patch which modifies the force_text and
force_bytes methods in django.utils.encoding. The modifications
basically involves adding an if statement.

if hasattr(s, '__call__'):
return s()

This would support setting the SECRET_KEY and database creds as
callables with no arguments. Example.

SECRET_KEY = lambda: get_creds(secret_key_id, type='privatekey')
. . .
DATABASES = {
'default' = {
. . .
'USER': lambda: get_creds(database_creds_id, type='username'),
'PASSWORD': lambda: get_creds(database_creds_id, type='password'),
},
. . .
}

My question is, should I submit a patch or might there be some other way
to address my use case? Also, I'm aware of the various examples which
call for storing secrets in a separate file. We cannot store secrets on
the local disk (this is partly the reason for the use of the system I
explained).

--
Andres

Marc Tamlyn

unread,
Jan 24, 2015, 10:57:23 AM1/24/15
to django-d...@googlegroups.com
I'm not sure what the benefit here would be - the settings are evaluated at start up time, not on every request and the server would need to be restarted for it to change.

A patch to db.connections which allows the username and password to be looked up on each new connection might be interesting, although I'd be concerned that for any reasonably high traffic site this would be happening a *lot*, normally during a user request. Something like caching it and then clearing the cache when it changes upstream would be more appropriate.

Marc



--
Andres

--
You received this message because you are subscribed to the Google Groups "Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/54C30C4D.4030302%40amazon.com.
For more options, visit https://groups.google.com/d/optout.

Riccardo Di Virgilio

unread,
Jan 25, 2015, 8:38:29 AM1/25/15
to django-d...@googlegroups.com
What you can try to do without modifying django code is to use custom settings class, which is a documented feature.


I'm doing that for my application, using a class that is using @property decorator to build dynamic settings.

I'm attaching the code that I'm currently using to use custom settings, this code replace the built in django.core.management.execute_from_command_line

What I'm doing is to create several settings that are shared across my django applications, and they are classes that can ineherit attributes, instead of being just modules.

the nice thing about this code is that you can create settings from a dict, from a module or from a class.

Take a look, maybe this can be a solution for your problem.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
manage.py
settings.py
execute.py

Riccardo Di Virgilio

unread,
Jan 25, 2015, 8:45:35 AM1/25/15
to django-d...@googlegroups.com

sorry the code you need to write with my solution in your settings file would be

class Settings(object):

    @property
    def SECRET_KEY(self):
        if self.DEBUG:
            return "abcd"
        return "12345"

Andres Mejia

unread,
Jan 25, 2015, 6:32:26 PM1/25/15
to django-d...@googlegroups.com
On 01/24/2015 10:56 AM, Marc Tamlyn wrote:
I'm not sure what the benefit here would be - the settings are evaluated at start up time, not on every request and the server would need to be restarted for it to change.

A patch to db.connections which allows the username and password to be looked up on each new connection might be interesting, although I'd be concerned that for any reasonably high traffic site this would be happening a *lot*, normally during a user request. Something like caching it and then clearing the cache when it changes upstream would be more appropriate.

This is addressed already by the system I referred to. I'll submit a patch for the database connections.


Marc

To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


-- 
Andres

Andres Mejia

unread,
Jan 25, 2015, 6:36:01 PM1/25/15
to django-d...@googlegroups.com
On 01/25/2015 08:45 AM, Riccardo Di Virgilio wrote:

sorry the code you need to write with my solution in your settings file would be

class Settings(object):

    @property
    def SECRET_KEY(self):
        if self.DEBUG:
            return "abcd"
        return "12345"




I'll take a look and see if this meets my needs. Thanks.


For more options, visit https://groups.google.com/d/optout.


-- 
Andres
Reply all
Reply to author
Forward
0 new messages