9

I'm trying to connect Django to a MySQL database which is accessible through an SSL connection. How do I configure this?

My first guess would be setting the 'OPTIONS' property of the database definition. However, I can't find info on what possible options to use. The option 'ssl': '/map/to/ca-cert.pem' does not work.

The following command seems to work:

mysql -h url.to.host -u lizard -p --ssl-ca=./ca-cert.pem

Edit: Ok I'm looking at the python-mysqldb documentation... maybe I can find the answer there.

Josh Correia
  • 3,807
  • 3
  • 33
  • 50
Jack Ha
  • 19,661
  • 11
  • 37
  • 41

4 Answers4

18

Django uses the Python MySQLdb library to interface with MySQL. Looking at the MySQLdb connection documentation, it looks like the ssl option requires a dictionary argument. So this might work:

'OPTIONS': {'ssl': {'key': '/map/to/ca-cert.pem'}}
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Thanks. It also works with 'ca' instead of 'key'. The answer was on this page: http://dev.mysql.com/doc/refman/5.5/en/mysql-ssl-set.html – Jack Ha Dec 01 '10 at 13:56
  • 5
    It seems that 'ca' is the correct option, 'key' on its own caused MySQL to not verify the contents. Read more about it here: http://stackoverflow.com/questions/7287088/ca-ssl-parameter-for-python-mysqldb-not-working-but-key-does and here: http://bugs.mysql.com/bug.php?id=62743 – PROGRAM_IX Jan 20 '14 at 18:04
13

The MySQL client must be provided with three keys:

  • CA cert
  • client cert
  • client key

See the MySQL documentation for the instructions for creating these keys and setting up the server.

NOTE: There is an open issue that seems to be related to using openssl v1.0.1 to create the certificates for mysql 5.5.x

This is an example entry for the Django settings file:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',  
        'NAME': '<DATABASE NAME>',                     
        'USER': '<USER NAME>',
        'PASSWORD': '<PASSWORD>',
        'HOST': '<HOST>', 
        'PORT': '3306',
        'OPTIONS':  {
            'ssl': {'ca': '<PATH TO CA CERT>',
            'cert': '<PATH TO CLIENT CERT>',
            'key': '<PATH TO CLIENT KEY>'
            }
        }
    }
}
Josh Correia
  • 3,807
  • 3
  • 33
  • 50
Drew
  • 6,311
  • 4
  • 44
  • 44
  • 3
    I'm not entirely sure the "must be" in the first sentence is correct unless cert+key **authentication** is being used (in contrast to just encrypting the network traffic). – jblaine Apr 24 '17 at 19:58
3

I was getting a "SSL connection error: SSL_CTX_set_default_verify_paths failed') "error when running python manage.py migrate

I used pip to install django-mysql-ssl package. It still wasn't working. I had to change "ca" to "ssl-ca" and now it works.

'OPTIONS':  {
                    'ssl': {'ssl-ca': '<PATH TO CA CERT>',

                            }
                      }

I'm not sure if it is actually using encryption, but it no longer throws an error. I am running local django app connected to an AWS mariaDB instance.

Edit: django-mysql-ssl package is not required starting from Django 1.8, as the functionality is built-in now. See Dependencies section in the package description here

Dependencies

This application is confirmed to work with Django 1.5. It should also work with Django 1.6-1.7. This plugin is not necessary for Django 1.8, as the capability is built into the core.

Benjamin
  • 3
  • 2
BBaker
  • 31
  • 2
  • I got the same error and `'ssl': {'ssl-ca': ''` worked for me too. Also, I see the path to the CA cert can be anything, even non-existent, and it still works fine. See https://stackoverflow.com/a/54543985/8645590. – Vikram Hosakote Feb 06 '19 at 16:13
  • _"I'm not sure if it is actually using encryption"_ @BBaker, the connection will be encrypted, I checked by doing `SHOW SESSION STATUS LIKE 'Ssl_cipher'`. – Vikram Hosakote Feb 06 '19 at 16:21
0

In case of SSL encrypted connection will probably need cipher parameter

DATABASE = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db_name',
        'USER': 'user',
        'PASSWORD': 'pass',
        'HOST': 'host',
        'PORT': '3306',
        'OPTIONS': {
            'ssl': {
                'ca': 'path/to/pem',
                'key': 'path/to/pem',
                'cert': 'path/to/pem',
                'cipher': 'AES128-SHA' #| 'AES128-SHA256' | 'DHE-RSA-AES256-SHA'
            }
        }
    }
}

MySQL passes a default cipher list to the SSL library. More details can be found here:

  1. https://dev.mysql.com/doc/refman/5.7/en/encrypted-connection-protocols-ciphers.html#encrypted-connection-cipher-configuration
  2. https://dev.mysql.com/doc/refman/5.7/en/encrypted-connection-protocols-ciphers.html#encrypted-connection-protocol-negotiation

Can't leave comments for @Drew answer, so let it be new one.

Volo
  • 143
  • 1
  • 7