背景
部署方式:docker
将项目从6.0升级到8.0后,除项目TargetFramework由net6.0更新为net8.0外。
再有就是将 Dockerfile 文件内
FROM mcr.microsoft.com/dotnet/aspnet:6.0
变更为
FROM mcr.microsoft.com/dotnet/aspnet:8.0
然后就遇到连接数据库出错问题,具体来说就是连接SQL Server 数据库不支持 TLS 1.2。
报错信息为:
Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: SSL Provider, error: 31 - Encryption(ssl/tls) handshake failed)
奇怪的是,在应用层,有两个应用,管理后台(Blazor Server)和 WebApi(asp.net core api),其余的依赖项目都是共用的,连接的数据为也是同一个,打包发布方式也一致。
但Blazor Server可以正常连接数据,api项目这个就一直报错(换电脑也一样)。
补充:
1、连接字符串 Encrypt=false;TrustServerCertificate=true; 都加了,没用
2、原先6.0时也遇到过类似问题,在
Dockerfile 文件中配置做如下配置是有效的,但升级到8.0后无效
RUN sed -i 's/TLSv1.2/TLSv1/g' /etc/ssl/openssl.cnf
或
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /usr/lib/ssl/openssl.cnf
8.0 Debian 容器映像已升级为 Debian 12
https://learn.microsoft.com/zh-cn/dotnet/core/compatibility/containers/8.0/debian-version
Debian 12 的新变化, OpenSSL 由 1.1.1n 更新到 3.0.8
https://www.debian.org/releases/stable/amd64/release-notes/ch-whats-new.zh-cn.html
要解决这个问题,应该配置 openssl 中 TLS v1.0
但,网上能找到的配置方案似乎都是过时的了。
不知道 OpenSSL 3.0 版本要怎么配置?
原先openssl.cnf 文件这样配置就行了
[ssl_protocols]
default_protocol = TLSv1
[system_default_sect]
MinProtocol = TLSv1
DEFAULT@SECLEVEL=1
但,镜像内的openssl.cnf 找不到这样的配置项,我手动添加上面的内容,重启容器没有效果。
猜测可能是 openssl 3.0 配置发生了变化或彻底不支持TLS v1.0了,但我在 openssl 官网上没找到具体的文档和配置方法。
有没有大佬可以解决这个问题?
2023-11-21 14:49
补充
将镜像切换到 ubuntu 或 Alpine 也是报同样的错,应该新版的都升级openssl到3.0+版本了, 在 askubuntu.com 上到一个类似的问题,按照上面的方面配置后,SQL Server是可以连了,但API程序中获取微信token的请求(https://api.weixin.qq.com/cgi-bin/token)
又报错了(但不是每次都报错,一般都是第一次请求会出错,再次请求又能请求到)。
Linux 上的 .NET 的默认 TLS 密码套件
现在,在 Linux 上,.NET 通过 SslStream 类或更高级别的操作(如通过 HttpClient 类的 HTTPS)执行 TLS/SSL 时,将遵循默认密码套件的 OpenSSL 配置
https://learn.microsoft.com/zh-cn/dotnet/core/compatibility/cryptography/5.0/default-cipher-suites-for-tls-on-linux
SQL Server 用的是哪个版本?
就是数据库版本有点老 2012,升级到8.0后,EF 也要做兼容性配置 UseCompatibilityLevel(110),但问题是 Blazor Server 项目也是连接的同一个数据哇。而且在本机(windows 10)上用VS调试或直接运行也是可以连接的。
@Adming: 的确与 SQL Server 版本有关,我们使用 SQL Server 2016 没这个问题
@dudu: 是的,具体就是看数据库是否支持TLS v1.2,2016已经能很好支持了。奇怪的是,我这两个项目,一个正常,一个不正常,也不晓得什么原因
@Adming: 可以试试换个 linux 发行版的镜像
@dudu: 嗯,是个方向,先前有试过用Alpine 镜像,结果直接报错了,也没细看。实在不行的话,真的要换镜像了。
官方之所以默认用debian,是因为它比Alpine要完善一点,比Ubuntu这些要小。
已经解决了,用默认的镜像可以(Debian 12版),但在 Alpine 中会影响 HttpClient 类的 HTTPS 请求(见上面补充)。
完整的 Dockerfile 配置如下
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY ./dist/GongWu_Api_Linux/ ./
# SQL Server 支持的SSL版本太高解决方案
# https://docs.microsoft.com/zh-cn/sql/connect/ado-net/sqlclient-troubleshooting-guide?view=sql-server-ver15
# 下列解决方案只适用于aspnet:6.0 aspnet:8.0镜像中openssl已更新到3.0,配置已发生变化
# 方案1
# RUN sed -i 's/TLSv1.2/TLSv1/g' /etc/ssl/openssl.cnf
# 方案2
# RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
# RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /etc/ssl/openssl.cnf
# RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
# RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /usr/lib/ssl/openssl.cnf
# 下列配置适用于 openssl3.0 修改TLSv1.2 为 TLSv1
# https://askubuntu.com/questions/1436476/ubuntu-22-04-sqlcmd-can-not-connect-to-ms-sql-server-2016/1445405#1445405
# openssl.cnf ****开始****
# openssl_conf = openssl_init
# [openssl_init]
# providers = provider_sect
# ssl_conf = ssl_sect
#
# [provider_sect]
# default = default_sect
# legacy = legacy_sect
#
# [default_sect]
# activate = 1
#
# [legacy_sect]
# activate = 1
#
# [ssl_sect]
# system_default = system_default_sect
#
# [system_default_sect]
# CipherString = DEFAULT:@SECLEVEL=0
# openssl.cnf ****结束****
# 修改默认的 openssl.cnf 配置
RUN sed -i 's/\[openssl_init\]/# \[openssl_init\]/g' /etc/ssl/openssl.cnf
RUN sed -i '$a\[openssl_init]' /etc/ssl/openssl.cnf
RUN sed -i '$a\providers = provider_sect' /etc/ssl/openssl.cnf
RUN sed -i '$a\ssl_conf = ssl_sect' /etc/ssl/openssl.cnf
RUN sed -i '$a\[provider_sect]' /etc/ssl/openssl.cnf
RUN sed -i '$a\default = default_sect' /etc/ssl/openssl.cnf
RUN sed -i '$a\legacy = legacy_sect' /etc/ssl/openssl.cnf
RUN sed -i '$a\[default_sect]' /etc/ssl/openssl.cnf
RUN sed -i '$a\activate = 1' /etc/ssl/openssl.cnf
RUN sed -i '$a\[legacy_sect]' /etc/ssl/openssl.cnf
RUN sed -i '$a\activate = 1' /etc/ssl/openssl.cnf
RUN sed -i '$a\[ssl_sect]' /etc/ssl/openssl.cnf
RUN sed -i '$a\system_default = system_default_sect' /etc/ssl/openssl.cnf
RUN sed -i '$a\[system_default_sect]' /etc/ssl/openssl.cnf
RUN sed -i '$a\CipherString = DEFAULT:@SECLEVEL=0' /etc/ssl/openssl.cnf
# 设置时区
# ENV TZ=Asia/Shanghai
# RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# RUN ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime && echo ${TZ} > /etc/timezone
# ENTRYPOINT ["bash" "-c" "cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime"]
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai'>/etc/timezone
EXPOSE 80
ENTRYPOINT ["dotnet", "ZY.GongWu.Web.dll"]
牛掰,今天刚好遇到,死活起不来
同样是.NET8 同样是sqlserver2008 ,我的还是连不了