You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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开始拒绝这种不符合规范的证书。

临时修复方案

  1. 禁用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
    }
    
  2. 回退Go版本:暂时降级到Go 1.22.x版本,该版本不会校验证书序列号的正负。

长期解决方案

等待MSSQL官方镜像修复自签名证书的生成逻辑,确保序列号为正整数。或者自行挂载符合规范的自定义证书到MSSQL容器:

  • 启动容器时添加挂载参数,将自定义证书文件挂载到容器内/var/opt/mssql/ssl目录
  • 设置环境变量MSSQL_SLCERT、MSSQL_SLPKEY指定证书和密钥路径

内容的提问来源于stack exchange,提问作者brettjames25

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:20:17