使用Testcontainers+MSSQL镜像遇x509负序列号证书解析错误求助
解决Testcontainers + MSSQL镜像的TLS握手错误:x509: negative serial number
最近使用Testcontainers搭配MSSQL镜像(已尝试多个版本)时,出现TLS握手失败错误,提示TLS Handshake failed: tls: failed to parse certificate from server: x509: negative serial number。本地WSL环境和Bitbucket流水线容器中均会触发该问题。
此前功能运行正常,错误出现时未更新Testcontainers或sqlx版本,当前使用Go 1.23。
相关日志
2024/10/07 13:27:35 🐳 Creating container for image mcr.microsoft.com/mssql/server:2022-latest 2024/10/07 13:27:35 ✅ Container created: d7e6e168b77b 2024/10/07 13:27:35 🐳 Starting container: d7e6e168b77b 2024/10/07 13:27:36 ✅ Container started: d7e6e168b77b 2024/10/07 13:27:36 ⏳ Waiting for container id d7e6e168b77b image: mcr.microsoft.com/mssql/server:2022-latest. Waiting for: &{timeout:<nil> Log:Recovery is complete. IsRegexp:false Occurrence:1 PollInterval:100ms} 2024/10/07 13:27:41 🔔 Container is ready: d7e6e168b77b database_test.go:173: Error Trace: database_test.go:173 Error: Received unexpected error: TLS Handshake failed: tls: failed to parse certificate from server: x509: negative serial number Test: TestConnection
测试初始化代码
import ( "context" "fmt" "testing" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go/modules/mssql" ) func setupDB(ctx context.Context, t *testing.T) (string, func(ctx context.Context) error) { container, err := mssql.Run(ctx, "mcr.microsoft.com/mssql/server:2022-latest", mssql.WithAcceptEULA(), ) require.NoError(t, err) conn, err := container.ConnectionString(ctx) require.NoError(t, err) return conn, container.Terminate } func TestConnection(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), testTimeout) defer cancel() conn, cleanup := setupDB(ctx, t) defer cleanup(ctx) db, err := sqlx.ConnectContext(ctx, "sqlserver", conn) assert.NoError(t, err) db.Ping() assert.NoError(t, err) assert.NotNil(t, db) }
问题原因与解决方案
这个错误是Go 1.23对x509证书的校验逻辑严格化导致的——MSSQL容器生成的自签名证书使用了负的序列号,而Go 1.23开始拒绝这种不符合规范的证书。
临时修复方案
禁用TLS连接:在连接字符串中添加
encrypt=disable参数,绕开证书校验。修改setupDB函数:func setupDB(ctx context.Context, t *testing.T) (string, func(ctx context.Context) error) { container, err := mssql.Run(ctx, "mcr.microsoft.com/mssql/server:2022-latest", mssql.WithAcceptEULA(), mssql.WithConnectionStringParams(map[string]string{ "encrypt": "disable", }), ) require.NoError(t, err) conn, err := container.ConnectionString(ctx) require.NoError(t, err) return conn, container.Terminate }回退Go版本:暂时降级到Go 1.22.x版本,该版本不会校验证书序列号的正负。
长期解决方案
等待MSSQL官方镜像修复自签名证书的生成逻辑,确保序列号为正整数。或者自行挂载符合规范的自定义证书到MSSQL容器:
- 启动容器时添加挂载参数,将自定义证书文件挂载到容器内
/var/opt/mssql/ssl目录 - 设置环境变量
MSSQL_SLCERT、MSSQL_SLPKEY指定证书和密钥路径
内容的提问来源于stack exchange,提问作者brettjames25
相关产品推荐
相关产品推荐

