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

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

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

Требования

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

  • Пользователь с доступом к sudo на каждом сервере.
  • На сервере MySQL нужно серверное программное обеспечение СУБД. Инструкции по установке можно найти в мануале Установка MySQL в Ubuntu 18.04 (разделы 1-3). Также нужно обязательно создать root-пользователя MySQL с парольной аутентификацией. Это необходимо для подключения MySQL через TCP, а не по Unix сокету.

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

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

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

Запустите сессию root-пользователя MySQL. Опция –р запрашивает пароль для входа. Опция –h позволяет указать хост, к которому нужно подключиться. В данном случае это loopback-интерфейс IPv4, или localhost. С его помощью клиент будет подключаться к TCP вместо локального сокета. MySQL пытается установить соединение через файл сокета Unix по умолчанию. Как правило, это быстрее и безопаснее, так как эти соединения можно создавать только локально и они не должны проходить все проверки и операции маршрутизации, которые проходят соединения TCP. Но TCP позволяет проверить статус SSL:

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.26, for Linux (x86_64) using  EditLine wrapper
Connection id:      9
Current database:
Current user:       root@localhost
SSL:         Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.7.26-0ubuntu0.18.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:         40 min 11 sec
Threads: 1  Questions: 33  Slow queries: 0  Opens: 113  Flush tables: 1  Open tables: 106  Queries per second avg: 0.013
--------------

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

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

exit

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

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

Чтобы включить поддержку SSL в MySQL, сначала нужно создать соответствующий сертификат и ключ. Утилита mysql_ssl_rsa_setup, которая поставляется вместе с MySQL 5.7+, позволяет ускорить этот процесс. Версия 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'
-----

Файлы будут созданы в каталоге данных MySQL, /var/lib/mysql. Проверьте созданные файлы:

sudo find /var/lib/mysql -name '*.pem' -ls
258930      4 -rw-r--r--   1 mysql    mysql        1107 May  3 16:43 /var/lib/mysql/client-cert.pem

258919      4 -rw-r--r--   1 mysql    mysql         451 May  3 16:43 /var/lib/mysql/public_key.pem


258925      4 -rw-------   1 mysql    mysql        1675 May  3 16:43 /var/lib/mysql/server-key.pem


258927      4 -rw-r--r--   1 mysql    mysql        1107 May  3 16:43 /var/lib/mysql/server-cert.pem


258922      4 -rw-------   1 mysql    mysql        1675 May  3 16:43 /var/lib/mysql/ca-key.pem


258928      4 -rw-------   1 mysql    mysql        1675 May  3 16:43 /var/lib/mysql/client-key.pem


258924      4 -rw-r--r--   1 mysql    mysql        1107 May  3 16:43 /var/lib/mysql/ca.pem


258918      4 -rw-------   1 mysql    mysql        1679 May  3 16:43 /var/lib/mysql/private_key.pem

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

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

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

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

sudo systemctl restart mysql

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

mysql -u root -p -h 127.0.0.1

Попробуйте снова запросить состояние переменных SSL, обратите внимание на значения переменных, которые имеют отношение к 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

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

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

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

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

На данный момент сервер 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 прослушивает только соединения, поступающие от 127.0.0.1. Это означает, что MySQL прослушивает только соединения от компьютера, на котором установлен сервер MySQL.

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

. . .
!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

Примечание: В качестве альтернативы вы можете установить внешний IP-адрес сервера MySQL. Но вам нужно будет обновить файл my.cnf, если вы перенесете свою базу данных на другой компьютер.

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

Затем перезапустите 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      13317/mysqld
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1293/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1293/sshd

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

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

sudo ufw allow mysql
Rule added
Rule added (v6)

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

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

Откройте сессию root-пользователя MySQL, чтобы создать удаленного пользователя:

mysql -u root -p

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

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

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

CREATE USER 'mysql_user'@'your_mysql_client_IP' IDENTIFIED BY 'password' REQUIRE SSL;

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

CREATE DATABASE example;
GRANT ALL ON example.* TO 'mysql_user'@'your_mysql_client_IP';

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

FLUSH PRIVILEGES;

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

exit

Теперь нужно попробовать создать удаленное соединение.

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

Чтобы подтвердить, что вы можете успешно подключиться к MySQL, вам необходимо установить пакет mysql-client на клиент MySQL.

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

ssh 8host@your_mysql_client_ip

Обновите индекс локальных пакетов:

sudo apt update

Установите пакет:

sudo apt install mysql-client

По запросу нажмите Enter.

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

mysql -u mysql_user -p -h your_mysql_server_IP

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

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

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

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

exit

Вы подтвердили, что можете подключиться к MySQL через SSL. Однако вы еще не убедились, что сервер MySQL сбрасывает небезопасные соединения. Чтобы проверить это, попробуйте подключиться еще раз, но на этот раз добавьте к команде login опцию —ssl-mode=disabled. Она позволит команде попытаться создать незашифрованное соединение:

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

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

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

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

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

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

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

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

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

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

Примечание: Процесс передачи сертификатов и клиентского ключа клиенту MySQL, описанный далее, включает отображение содержимого каждого файла с помощью команды cat, копирование этого содержимого в буфер обмена и вставку его в новый файл на клиентской машине. Эти файлы можно скопировать напрямую с помощью таких программ, как scp или sftp, но для этого необходимо настроить для обоих серверов ключи SSH, чтобы они могли обмениваться данными.

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

Читайте также: Установка SSH-ключей в Ubuntu 18.04

В домашнем каталоге создайте каталог для хранения сертификатов, 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 'mysql_user'@'mysql_client_IP' REQUIRE X509;

Сбросьте привилегии:

FLUSH PRIVILEGES;

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

exit

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

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

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

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

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

mysql -u mysql_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

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

Tags: , , , ,