Docker容器中使用sqlcmd连接SQL Server 2016时出现TLS 1.2握手错误
嘿,我碰到过几乎一模一样的坑!结合你给出的环境信息,核心问题其实是Debian 12容器里的OpenSSL默认安全配置和SQL Server 2016的TLS 1.2套件不兼容,咱们一步步来解决:
先把关键背景理清楚,省得走弯路:
- 你的宿主机Ubuntu 22.04能正常连接,是因为它的OpenSSL 3.0.2默认安全级别(SECLEVEL)是1,刚好兼容SQL Server 2016支持的TLS 1.2套件;但Debian 12的OpenSSL 3.0.14默认SECLEVEL是2,直接禁用了SQL Server 2016依赖的一些旧套件(比如SHA-1签名的套件),所以握手直接失败。
下面是具体的解决步骤,按从简到繁的优先级来:
1. 先确认问题根源
先在容器里用openssl命令测试TLS 1.2握手,100%定位是不是套件不匹配:
openssl s_client -connect "$UTT_SQLDB_SERVERNAME":1433 -tls1_2
如果输出里出现handshake failure,那直接坐实是套件兼容问题,往下走就对了。
2. 临时指定配置运行sqlcmd(容器环境首推)
不用改系统全局配置,直接在运行sqlcmd的时候用一个兼容的临时OpenSSL配置:
首先在容器里创建一个custom_openssl.cnf文件:
[default_conf] ssl_conf = ssl_sect [ssl_sect] system_default = system_default_sect [system_default_sect] MinProtocol = TLSv1.2 CipherString = DEFAULT@SECLEVEL=1
然后用这个配置启动sqlcmd:
OPENSSL_CONF=./custom_openssl.cnf sqlcmd \ --server "$UTT_SQLDB_SERVERNAME" \ --database-name "$UTT_SQLDB_DATABASE" \ --user-name "$UTT_SQLDB_USERNAME" \ --password "$UTT_SQLDB_PASSWORD"
这个方法最干净,不会影响容器里其他应用的OpenSSL配置。
3. 全局修改容器的OpenSSL配置(长期生效用)
如果你的容器只用来连接这个SQL Server,可以直接改全局配置一劳永逸:
编辑/etc/ssl/openssl.cnf,找到[default_conf]段,确保下面有ssl_conf = ssl_sect,然后添加/修改以下内容:
[ssl_sect] system_default = system_default_sect [system_default_sect] MinProtocol = TLSv1.2 CipherString = DEFAULT@SECLEVEL=1
改完之后重新运行sqlcmd就生效了。
4. 强制ODBC驱动使用TLS 1.2
另外还要确保ODBC驱动不会尝试用更高版本的TLS(SQL Server 2016不支持TLS 1.3),编辑/etc/odbcinst.ini里的ODBC Driver 17 for SQL Server段,加上强制TLS 1.2的配置:
[ODBC Driver 17 for SQL Server] Description=Microsoft ODBC Driver 17 for SQL Server Driver=/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.10.so.1.1 UsageCount=1 SSLProtocol=TLSv1.2
最后排查网络兜底
如果上面的步骤都试过还是不行,先确认容器能通SQL Server的1433端口:
nc -zv "$UTT_SQLDB_SERVERNAME" 1433
不过你宿主机能连,大概率网络是通的,这步只是兜底排查。
备注:内容来源于stack exchange,提问作者tvanbesi

