Вопрос или проблема
Ошибка рукопожатия шифровального набора TLS 1.2 при подключении к SQL Server с помощью sqlcmd
Я пытаюсь создать контейнер Docker для манипуляции данными из SQL Server.
Описание проблемы и вовлеченных устройств
Вот список соответствующих устройств:
- Контейнер Docker: ОС – Debian 12.
- Хост-машина: Ubuntu 22.04.
- SQL Server: версия 2016 13.0.2026. Работает на виртуальной машине Windows Server 2012R2. И нет, я не могу обновить ни одно из них (я спрашивал…).
Я использую точно те же учетные данные (взятые из того же .env файла, чтобы избежать ошибок).
Я могу подключиться через sqlcmd с хоста (используя sqlcmd v1.5.0, ODBC 17 и openssl 3.0.2-0ubuntu1.18).
Я использую эту команду для подключения с хоста:
sqlcmd \
--server "$UTT_SQLDB_SERVERNAME" \
--database-name "$UTT_SQLDB_DATABASE" \
--user-name "$UTT_SQLDB_USERNAME" \
--password "$UTT_SQLDB_PASSWORD"
Но из контейнера я не могу (используя sqlcmd 17.10.0001.1 Linux, ODBC 17 и openssl 3.0.14-1~deb12u2):
Я использую эту команду для подключения из контейнера:
sqlcmd \
-S "$UTT_SQLDB_SERVERNAME" \
-U "$UTT_SQLDB_USERNAME" \
-P "$UTT_SQLDB_PASSWORD" \
-d "$UTT_SQLDB_DATABASE"
Проблема с брандмауэром отсутствует, так как я могу telnet и ping SQL Server из контейнера.
Сообщения об ошибках
В контейнере я получаю следующее сообщение об ошибке:
root@50f7a7519b2b:/var/www/html# sqlcmd -S $UTT_SQLDB_SERVERNAME -U $UTT_SQLDB_USERNAME -P $UTT_SQLDB_PASSWORD -d $UTT_SQLDB_DATABASE
Sqlcmd: Ошибка: Microsoft ODBC Driver 17 для SQL Server : TCP Provider: код ошибки 0x2746.
Sqlcmd: Ошибка: Microsoft ODBC Driver 17 для SQL Server : клиент не может установить соединение.
А в журналах SQL Server я получаю следующие два сообщения об ошибках (я перевел их с французского):
Код ошибки TLS 40: Это указывает на сбой при установлении соединения во время обмена TLS. Это происходит, когда клиент и сервер не могут согласовать протоколы шифрования или шифры.
Ошибка SChannel 1205: Это ошибка Windows, связанная с SChannel (Безопасный канал), который является компонентом, ответственным за обработку шифрования SSL/TLS. Ошибка 1205, как правило, означает, что имел место несоответствие в конфигурации TLS между клиентом и сервером.
Что я пробовал
Так как это, похоже, проблема с набором шифров, я пытался подключиться напрямую через openssl вот так (из контейнера):
root@50f7a7519b2b:/var/www/html# openssl s_client -connect $UTT_SQLDB_SERVERNAME:1433 -tls1_2
CONNECTED(00000003)
root@50f7a7519b2b:/var/www/html# openssl s_client -connect $UTT_SQLDB_SERVERNAME:1433 -tls1_1
CONNECTED(00000003)
root@50f7a7519b2b:/var/www/html# openssl s_client -connect $UTT_SQLDB_SERVERNAME:1433 -tls1
CONNECTED(00000003)
И это работает. Что меня сбивает с толку.
Я также не понимаю, почему я могу подключаться с хоста, но не из контейнера, используя эквивалентные команды и схожие ОС?
Я также пытался запустить контейнер в режиме сети хоста. Без успеха.
Ответ или решение
Проблема, с которой вы столкнулись, связана с ошибкой рукопожатия TLS при попытке подключения к SQL Server из Docker-контейнера. Хотя вы можете успешно подключиться к серверу из хостовой системы, но не можете сделать это из контейнера — это довольно распространенная проблема, учитывая, что в окружениях Docker могут быть разные конфигурации.
Анализ проблемы
-
Сертификаты и протоколы: Хотя вы можете установить соединение с SQL Server с помощью OpenSSL, это не обязательно означает, что ваш клиент
sqlcmd
может использовать те же шифры, что и OpenSSL. Версия ODBC драйвера и его совместимость с TLS могут вызывать проблемы с шифрованием. -
Разные версии библиотек: На хост-системе используется
openssl 3.0.2
, в то время как в контейнереopenssl 3.0.14
. Версии библиотек могут иметь разные настройки по умолчанию, что может влиять на совместимость шифров. - Конфигурация Docker: Контейнер может иметь разные сетевые настройки и зависимости от конфигурации Docker. Возможно, что в контейнере что-то мешает правильному использованию ODBC драйвера.
Рекомендации по решению проблемы
-
Проверка шифров: Убедитесь, что ODBC драйвер, используемый в контейнере, поддерживает те же шифры, что и сервер. Вы можете выполнить команду для отображения доступных шифров:
openssl ciphers -v
Убедитесь, что необходимые для работы шифры и протоколы включены.
-
Обновление ODBC драйвера: Убедитесь, что вы используете последнюю версию ODBC драйвера 17 для SQL Server. Иногда обновления могут содержать исправления, которые улучшают совместимость.
-
Проверка настроек TLS на сервере: Убедитесь, что сервер SQL настроен для поддержки необходимых протоколов и шифров. Возможно, потребуется изменить настройки на стороне сервера.
-
Запуск контейнера с использованием
--network host
: Если вы еще не попробовали это, попробуйте запустить контейнер с флагом--network host
. Это обеспечит использование сетевых настроек вашего хоста и может помочь с проблемами совместимости.docker run --network host your-docker-image
-
Анализ логов SQL Server: Обратите внимание на дополнительные ошибки в журналах SQL Server. Они могут дать дополнительную информацию о причинах при отказе в подключении.
- Протестируйте на другой версии контейнера: Возможно, у вас изменится поведение при использовании другого базового образа Docker. Попробуйте начать с базового образа, отличного от Debian 12, например, с Ubuntu.
Пример команды для тестирования
Попробуйте следующее, чтобы увидеть, может ли sqlcmd
подключиться:
sqlcmd -S "$UTT_SQLDB_SERVERNAME" -U "$UTT_SQLDB_USERNAME" -P "$UTT_SQLDB_PASSWORD" -d "$UTT_SQLDB_DATABASE" -N
Флаг -N
требует, чтобы соединение было защищенным.
Заключение
Если ни одно из решений не поможет, возможно, стоит рассмотреть возможность использования другого клиента, например, sql-cli
или другого инструмента, который может использовать другие механизмы подключения. Кроме того, не забудьте проверить справочную документацию Microsoft и Bugzilla для известного поведения, связанного с их ODBC драйверами и соответствующими библиотеками.