Site icon 8HOST.COM

Настройка SSL/TLS для MySQL в Ubuntu 16.04

MySQL – самая популярная в мире реляционная система управления базами данных с открытым исходным кодом. Современные менеджеры пакетов упрощают запуск MySQL, однако после установки следует выполнить дополнительную настройку СУБД. В частности, это касается безопасности данных.

По умолчанию MySQL принимает только локальные соединения. Прежде чем настроить поддержку удалённых соединений, очень важно позаботиться о безопасности. Данное руководство поможет настроить MySQL на сервере Ubuntu 16.04 для поддержки удалённых соединений с помощью шифрования SSL/TLS.

Требования

Для работы вам понадобятся два сервера Ubuntu 16.04 (первый будет использоваться в качестве сервера MySQL, второй – в качестве клиента).

sudo apt-get update
sudo apt-get install mysql-client

Проверка состояния SSL/TLS

Примечание: Выполните этот раздел на сервере MySQL.

Подключитесь к серверу MySQL и проверьте текущее состояние SSL/TLS.

Запустите сессию root-пользователя MySQL. Флаг –h позволяет указать локальный loopback-интерфейс IPv4, чтобы клиент подключался к TCP вместо локального сокета. Это позволит проверить статус SSL для TCP-соединений:

mysql -u root -p -h 127.0.0.1

По запросу введите root-пароль MySQL, после чего откроется интерактивная сессия.

Запросите состояние переменных SSL/TLS:

SHOW VARIABLES LIKE '%ssl%';
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| have_openssl  | DISABLED |
| have_ssl      | DISABLED |
| ssl_ca        |          |
| ssl_capath    |          |
| ssl_cert      |          |
| ssl_cipher    |          |
| ssl_crl       |          |
| ssl_crlpath   |          |
| ssl_key       |          |
+---------------+----------+
9 rows in set (0.01 sec)

Переменные have_openssl и have_ssl отключены (отмечены как DISABLED). Это значит, что сервер поддерживает функции SSL, но пока что шифрование не включено.

Проверьте состояние текущего соединения:

\s
--------------
mysql  Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using  EditLine wrapper
Connection id:      30
Current database:
Current user:       root@localhost
SSL:         Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.7.17-0ubuntu0.16.04.1 (Ubuntu)
Protocol version:   10
Connection:      127.0.0.1 via TCP/IP
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    utf8
Conn.  characterset:    utf8
TCP port:       3306
Uptime:         3 hours 38 min 44 sec
Threads: 1  Questions: 70  Slow queries: 0  Opens: 121  Flush tables: 1  Open tables: 40  Queries per second avg: 0.005
--------------

На данный момент подключение не использует SSL даже несмотря на то, что это TCP-подключение.

Закройте текущую сессию MySQL:

exit

Генерирование SSL/TLS-сертификатов и ключей

Примечание: Данный раздел также выполняется на сервере MySQL.

Чтобы включить поддержку SSL в MySQL, сначала нужно сгенерировать соответствующий сертификат и ключ. Утилита mysql_ssl_rsa_setup, которая поставляется вместе с MySQL 5.7+, позволяет ускорить этот процесс. Ubuntu 16.04 предоставляет версию MySQL, совместимую с этой утилитой.

Файлы будут созданы в каталоге данных MySQL, /var/lib/mysql. Процесс MySQL должен иметь возможность читать сгенерированные файлы, поэтому в качестве владельца сгенерированных файлов нужно указать пользователя mysql:

sudo mysql_ssl_rsa_setup --uid=mysql

При этом будет сгенерирован такой вывод:

Generating a 2048 bit RSA private key
...................................+++
.....+++
writing new private key to 'ca-key.pem'
-----
Generating a 2048 bit RSA private key
......+++
.................................+++
writing new private key to 'server-key.pem'
-----
Generating a 2048 bit RSA private key
......................................................+++
.................................................................................+++
writing new private key to 'client-key.pem'
-----

Проверьте созданные файлы:

sudo find /var/lib/mysql -name '*.pem' -ls
256740      4 -rw-r--r--   1 mysql    mysql        1078 Mar 17 17:24 /var/lib/mysql/server-cert.pem
256735      4 -rw-------   1 mysql    mysql        1675 Mar 17 17:24 /var/lib/mysqlsql/ca-key.pem<^>
256739      4 -rw-r--r--   1 mysql    mysql         451 Mar 17 17:24 /var/lib/mysqlsql/public_key.pem<^>
256741      4 -rw-------   1 mysql    mysql        1679 Mar 17 17:24 /var/lib/mysqlsql/client-key.pem<^>
256737      4 -rw-r--r--   1 mysql    mysql        1074 Mar 17 17:24 /var/lib/mysqlsql/ca.pem<^>
256743      4 -rw-r--r--   1 mysql    mysql        1078 Mar 17 17:24 /var/lib/mysqlsql/client-cert.pem<^>
256736      4 -rw-------   1 mysql    mysql        1675 Mar 17 17:24 /var/lib/mysqlsql/private_key.pem<^>
256738      4 -rw-------   1 mysql    mysql        1675 Mar 17 17:24 /var/lib/mysqlsql/server-key.pem<^>

В последнем столбце показаны имена сгенерированных файлов. Столбцы, в которых содержится значение «mysql», указывают, что сгенерированные файлы имеют принадлежат правильному пользователю и группе.

Эти файлы – это ключи и сертификаты для центра сертификации (название файла начинается с «ca»), а также для сервера и клиента MySQL (файлы с названиями server и client соответственно). Файлы private_key.pem и public_key.pem MySQL использует для безопасной передачи паролей вне SSL.

Включение SSL на сервере MySQL

Современные версии MySQL ищут файлы сертификатов в каталоге данных MySQL при запуске сервера. Потому для включения поддержки SSL не нужно изменять конфигурацию MySQL.

Достаточно просто перезапустить сервис MySQL:

sudo systemctl restart mysql

После перезапуска откройте сессию MySQL. Клиент MySQL автоматически попытается подключиться по SSL, если сервер поддерживает такие изменения.

mysql -u root -p -h 127.0.0.1

Попробуйте снова запросить состояние переменных SSL:

SHOW VARIABLES LIKE '%ssl%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| have_openssl  | YES             |
| have_ssl      | YES             |
| ssl_ca        | ca.pem          |
| ssl_capath    |                 |
| ssl_cert      | server-cert.pem |
| ssl_cipher    |                 |
| ssl_crl       |                 |
| ssl_crlpath   |                 |
| ssl_key       | server-key.pem  |
+---------------+-----------------+
9 rows in set (0.00 sec)

Теперь вместо DISABLED переменные have_openssl и have_ssl имеют значение YES. Кроме того, переменные ssl_ca, ssl_cert и ssl_key теперь содержат имена соответствующих файлов.

Снова введите команду:

\s
--------------
. . .
SSL:            Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection:      127.0.0.1 via TCP/IP
. . .
--------------

На этот раз отображается специальный SSL-шифр, а это значит, что для защиты соединения используется SSL.

Вернитесь в оболочку:

exit

Теперь сервер поддерживает шифрование данных.

Настройка защищенных подключений для удаленных клиентов

Теперь, когда сервер поддерживает SSL, можно начать настройку безопасного удаленного доступа. Для этого необходимо:

Настройка удаленного доступа

На данный момент сервер MySQL поддерживает подключения SSL от клиентов. Но он также поддерживает и незашифрованные удалённые соединения, а это небезопасно.

Чтобы исправить это, нужно включить опцию require_secure_transport, которая включает ограничение удалённых соединений и поддерживает только SSL или соединения по локальному сокету Unix.

Поскольку сокеты доступны только внутренним подключениям сервера, единственным способом подключения, доступным для удаленных пользователей, будет SSL.

Чтобы включить этот параметр, откройте файл /etc/mysql/my.cnf в текстовом редакторе:

sudo nano /etc/mysql/my.cnf

В файле вы найдёте две директивы !includedir для ссылки на дополнительные конфигурационные файлы. Нужно разместить свои настройки под этими строками, чтобы они переопределяли конфликтующие настройки.

Создайте раздел [mysqld], чтобы определить процесс MySQL. Добавьте директиву require_secure_transport со значением ON.

. . .
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[mysqld] # Require clients to connect either using SSL
# or through a local socket file
require_secure_transport = ON

Эта строка делает обязательным шифрование соединений.

По умолчанию MySQL прослушивает только соединения, поступающие от локальной машины. Чтоб ынастроить прослушивание удалённых соединений, укажите другой интерфейс в bind-address.

Чтобы система MySQL могла принимать соединения на любой свой интерфейс, укажите в bind-address значение 0.0.0.0.

. . .
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[mysqld] # Require clients to connect either using SSL
# or through a local socket file
require_secure_transport = ON
bind-address = 0.0.0.0

Сохраните и закройте файл.

Перезапустите MySQL:

sudo systemctl restart mysql

Убедитесь, что MySQL прослушивает 0.0.0.0 вместо 127.0.0.1.

sudo netstat -plunt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      4330/mysqld
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1874/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1874/sshd

Как видите, теперь MySQL прослушивает 0.0.0.0, то есть поддерживает соединения на всех интерфейсах.

Теперь нужно открыть MySQL в брандмауэре.

sudo ufw allow mysql
Rule added
Rule added (v6)

Настройка удаленного пользователя MySQL

Теперь сервер MySQL прослушивает удаленные соединения, но в настоящее время нет пользователей, которые могли бы подключаться с внешних машин.

Откройте сессию root-пользователя MySQL:

mysql -u root -p

Создайте нового удалённого пользователя с помощью команды CREATE USER.

Используйте IP-адрес клиентского компьютера в качестве хоста нового пользователя, чтобы ограничить подключение к этой машине.

На случай если опция require_secure_transport будет отключена, добавьте REQUIRE SSL, чтобы ограничить пользователя только SSL-соединениями.

CREATE USER 'remote_user'@'mysql_client_IP' IDENTIFIED BY 'password' REQUIRE SSL;

Затем предоставьте пользователю права на требуемые базы данных или таблицы. Для примера создайте базу данных example и передайте новому пользователю право на неё:

CREATE DATABASE example;
GRANT ALL ON example.* TO 'remote_user'@'mysql_client_IP';

Затем очистите привилегии, чтобы обновить настройки БД:

FLUSH PRIVILEGES;

Закройте оболочку MySQL:

exit

Тестирование удалённых подключений

Примечание: Этот подраздел нужно выполнить на клиенте MySQL.

Подключитесь к клиенту MySQL и убедитесь, что можете создать удалённое подключение к серверу. Опция –u указывает удалённого пользователя, -h задаёт IP-адрес MySQL.

mysql -u remote_user -p -h mysql_server_IP

Предоставьте пароль указанного в команде пользователя, после чего вы будете подключены к удалённому серверу.

Убедитесь, что подключение шифруется:

\s
--------------
. . .
SSL:         Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection:      mysql_server_IP via TCP/IP
. . .
--------------

Вернитесь в оболочку системы:

exit

Попробуйте создать соединение без шифрования:

mysql -u remote_user -p -h mysql_server_IP --ssl-mode=disabled

После запроса пароля соединение будет сброшено:

ERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_server_IP' (using password: YES)

Как видите, поддерживаются только SSL-соединения, а незашифрованные соединения сбрасываются.

На данный момент сервер MySQL поддерживает безопасные удалённые подключения. В целом, этого достаточно для обеспечения безопасности данных. Однако есть некоторые дополнительные рекомендации, которые можно использовать.

Проверка подлинности подключений MySQL (опционально)

В настоящее время сервер MySQL использует SSL-сертификат, подписанный сгенерированным на локальной машине центром сертификации (CA). Сертификата сервера и пары ключей будет достаточно для шифрования входящих соединений.

Центр сертификации может также подтвердить подлинность сервера или клиента, но на данный момент эта функция не используется. Создайте сертификат CA и ключи для клиентов, тогда обе стороны смогут предоставить сертификаты, подписанные доверенным центром и подтверждающие их подлинность. Это предотвратит подделку соединений вредоносными серверами.

Чтобы настроить проверку подлинности, нужно:

Перемещение сертификата на клиент

Передайте файлы сертификата клиента MySQL с сервера на клиентскую машину.

Подключитесь к клиенту MySQL. В домашнем каталоге создайте каталог для хранения сертификатов, client-ssl.

mkdir ~/client-ssl

Ключ сертификата нужно хранить в секрете. Ограничьте доступ к каталогу, в котором хранится ключ.

chmod 700 ~/client-ssl

Теперь права доступа есть только у текущего пользователя.

Скопируйте сертификат с сервера на клиент.

Перейдите на сервер MySQL и отобразите содержимое следующего файла:

sudo cat /var/lib/mysql/ca.pem
-----BEGIN CERTIFICATE-----
. . .
-----END CERTIFICATE-----

Скопируйте весь результат (включая строки BEGIN CERTIFICATE и END CERTIFICATE).

Вернитесь на клиент MySQL, создайте файл в каталоге для сертификатов:

nano ~/client-ssl/ca.pem

Вставьте в него скопированный сертификат. Сохраните и закройте файл.

Вернитесь на сервер MySQL и отобразите содержимое файла:

sudo cat /var/lib/mysql/client-cert.pem
-----BEGIN CERTIFICATE-----
. . .
-----END CERTIFICATE-----

Снова скопируйте весь результат (включая строки BEGIN CERTIFICATE и END CERTIFICATE).

Перейдите на клиент MySQL и создайте файл в каталоге для сертификатов:

nano ~/client-ssl/client-cert.pem

Вставьте в него скопированный сертификат, сохраните и закройте файл.

Снова вернитесь на сервер MySQL и отобразите содержимое следующего файла:

sudo cat /var/lib/mysql/client-key.pem
-----BEGIN RSA PRIVATE KEY-----
. . .
-----END RSA PRIVATE KEY-----

Скопируйте полученный результат, включая строки BEGIN CERTIFICATE и END CERTIFICATE.

Вернитесь на клиент MySQL, создайте файл в каталоге:

nano ~/client-ssl/client-key.pem

В этот файл вставьте скопированные данные, сохраните и закройте файл.

Теперь у клиента есть все необходимые данные для подтверждения подлинности соединения.

Настройка удаленного пользователя

В настоящее время клиент MySQL имеет все необходимые файлы сертификата, которые можно использовать при подключении к серверу. Однако сервер по-прежнему не поддерживает сертификаты клиента.

Перейдите на сервер MySQL. Откройте сессию пользователя root в MySQL:

mysql -u root -p

Измените параметры удалённого пользователя. Вместо REQUIRE SSL укажите REQUIRE X509. Теперь, помимо обязательного SSL-соединения, сервер будет запрашивать у удалённого пользователя сертификат, подписанный центром, которому доверяет сервер MySQL.

Чтобы изменить параметры пользователя, введите:

ALTER USER 'remote_user'@'mysql_client_IP' REQUIRE X509;

Очистите привилегии:

FLUSH PRIVILEGES;

Вернитесь в стандартную оболочку:

exit

Тестирование проверки подлинности соединений

Теперь нужно убедиться, что сервер запрашивает сертификат клиента.

Перейдите на клиентскую машину MySQL и попробуйте создать соединение без сертификата.

mysql -u remote_user -p -h mysql_server_IP
ERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_client_IP' (using password: YES)

Как видите, без сертификата клиент не сможет создать удалённое подключение.

Теперь добавьте в команду опции –ssl-ca, –ssl-cert и –ssl-key, в которых нужно указать путь к соответствующим файлам сертификата:

mysql -u remote_user -p -h mysql_server_IP --ssl-ca=~/client-ssl/ca.pem --ssl-cert=~/client-ssl/client-cert.pem --ssl-key=~/client-ssl/client-key.pem

Сервер должен принять такое подключение. Закройте сессию MySQL:

exit

Создание конфигурационного файла клиента

Чтобы не указывать файлы сертификатов при каждом подключении, можно создать простой файл конфигурации клиента MySQL.

Подключитесь к клиенту MySQL.

Откройте домашний каталог и создайте в нём скрытый файл ~/.my.cnf:

nano ~/.my.cnf

Добавьте в файл раздел [client]. В нём можно указать опции ssl-ca, ssl-cert и ssl-key со всеми путями к соответствующим файлам.

[client] ssl-ca = ~/client-ssl/ca.pem
ssl-cert = ~/client-ssl/client-cert.pem
ssl-key = ~/client-ssl/client-key.pem

Опция ssl-ca проверяет сертификат сервера MySQL и подтверждает, что он подписан центром, которому можно доверять.

Опции ssl-cert и ssl-key указывают пути к файлам сертификата и ключа, которые позволяют подтвердить подлинность сертификата.

Сохраните и закройте файл.

Попробуйте подключиться к серверу MySQL, не добавляя в команду опции –ssl-ca, –ssl-cert и –ssl-key.

mysql -u remote_user -p -h mysql_server_ip

Теперь клиент и сервер могут подтвердить свою подлинность.