Giter Club home page Giter Club logo

django-mysql-rds's Introduction

django-mysql-rds

A Django db backend for connecting to RDS MySQL instances using SSL db auth tokens.

Use

I'd recommend understanding what you're doing and why before dropping this in, but chances are that you have a DATABASES dict that looks something like:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': DBNAME,
        'USER': USER,
        'PASSWORD': aws_client.generate_db_auth_token(HOST, PORT, USER),
        'HOST': HOST,
        'PORT': PORT,
        'OPTIONS': {
            'ssl': {
                'ca': 'certs/rds-cert.pem'
            }
        }
    }
}

And you've discovered that after ~15 minutes you make a request and receive Access Denied for user@instance because the password has expired.

This package allows you to generate the password at connection time by passing a callable instead:

def generate_pw():
    return aws_client.generate_db_auth_token(HOST, PORT, USER)

DATABASES = {
    'default': {
        'ENGINE': 'mysql_rds.backend',
        'NAME': DBNAME,
        'USER': USER,
        'PASSWORD': generate_pw,
        'HOST': HOST,
        'PORT': PORT,
        'CONN_MAX_AGE': 900,
        'OPTIONS': {
            'ssl': {
                'ca': 'certs/rds-cert.pem'
            }
        }
    }
}

I recommend setting a CONN_MAX_AGE of 900 as the generated auth token expires after 900 seconds. This ensures that connections requiring a refresh recreated. You can pass any function as the password and it will be evaluated at connection time. For testing locally if you cannot connect to directly to RDS you can do something like:

def generate_pw():
    return 'password'

Installation

pip install django-mysql-rds

or

git clone [email protected]:cramshaw/django-mysql-rds.git

Why?

When I searched for a way to connect to an AWS RDS MySQL instance using SSL inside Django, I was unable to find anything that could handle the fact that the db auth token generated by AWS would expire every 15 minutes.

The problem is that when anything in the settings module changes, Django needs to reload. This isn't practical in a long running web app. I needed a way for the password to be generated at the time of connection.

How?

On close inspection of the django.db.backends.mysql code, it became clear that the DatabaseWrapper.get_connection_params method takes the settings dict, and transforms it into the kwargs that are passed to mysql.connect. I have subclassed this and extended to recognise if the password passed in is a callable, and if so, to call it and pass on the returned value. This leads to Django receiving a fresh password every time a connection is created.

A very similar thing happens in the DatabaseClient.settings_to_cmd_args which is used for things like dumping and loading data. This has also been subclassed and changed to ensure the password generation method actually runs before attempting to create a run a shell.

Caveats

Whilst this works for me running django==2.2 and should work exactly the same as the built in MySQL backend, there are no guarantees.

I only needed this to work for MySQL. I haven't explored whether RDS does the same for Postgres or other databases, but the same principle ought to apply.

Running Tests

Tests require https://pypi.org/project/mysqlclient/ installed.

python -m unittest tests/test*

Packaging

Bump version in setup.py then:

rm -rf dist/
python3 setup.py sdist bdist_wheel
python3 -m twine upload dist/*

django-mysql-rds's People

Contributors

cramshaw avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.