通过SSL连接golang mgo和Mongo的方法

3
我正在尝试在本地设置Mongo以测试https://www.compose.com/articles/connect-to-mongo-3-2-on-compose-from-golang/中“有点难”部分所描述的设置。 Mongo 我有一套可工作的自签名凭据和Mongo设置。我已经包含了密钥,因为这些只会在开发过程中使用,以确保Mongo SSL代码正常工作。 mongo ssl config 使用此配置时,通过运行以下命令:
mongod --config config/location

配置如下:
net:
  port: 27017
  ssl:
    mode: requireSSL
    CAFile: /data/mongo/ca.crt
    PEMKeyFile: /data/mongo/server.pem
    allowInvalidHostnames: true
    allowConnectionsWithoutCertificates: true

我可以通过以下方式连接到数据库

mongo --ssl --sslCAFile /data/mongo/ca.crt

Golang

func NewSession(url string, ca string) (m *mgo.Session, err error) {
    roots := x509.NewCertPool()
    roots.AppendCertsFromPEM([]byte(ca))

    tlsConfig := &tls.Config{}
    tlsConfig.RootCAs = roots

    url = strings.TrimSuffix(url, "?ssl=true")
    dialInfo, err := mgo.ParseURL(url)
    dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
        conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
        return conn, err
    }

    //Here it is the session. Up to you from here ;)
    session, err := mgo.DialWithInfo(dialInfo)
    if err != nil {
        return m, err
    }

    session.SetMode(mgo.Monotonic, true)

    return session, nil
}

结果

Golang程序试图连接并遇到了10秒的超时。在session顶部的fmt函数显示正确的文件已经被传入ca变量。

Mongo日志如下:

utumongo_1         | 2017-07-27T08:09:14.964+0000 I NETWORK  [initandlisten] connection accepted from 172.19.0.4:57474 #30 (1 connection now open)
utumongo_1         | 2017-07-27T08:09:14.966+0000 E NETWORK  [conn30] SSL: error:14094412:SSL routines:SSL3_READ_BYTES:sslv3 alert bad certificate
utumongo_1         | 2017-07-27T08:09:14.967+0000 I NETWORK  [conn30] end connection 172.19.0.4:57474 (0 connections now open)

编辑 更新了Mongo配置

1个回答

3
你将什么作为“ca”参数传递给“NewSession”?这应该是PEM编码的CA证书字节,而不是CA证书文件名。“AppendCertsFromPEM”如果成功添加了任何证书到池中,则会返回“true”。
本文已经展示了如何实现此操作的代码:
if ca, err := ioutil.ReadFile("myPEM"); err == nil { 
    roots.AppendCertsFromPEM(ca)
}

SSL错误意味着客户端拒绝了服务器证书。我怀疑这是因为您的自签名证书没有正确添加到池中造成的。 编辑 我使用您的配置在本地运行了一个mongo副本。使用docker,命令如下:
docker run --rm -ti -v $(pwd):/data/mongo --net=host mongo -f /data/mongo/mongo.yaml

当在您提取配置文件的位置运行时,使用Go中的NewSession函数显示tls.Dial由于缺乏任何主题访问名称(SAN)扩展而返回错误,如下面的评论所述。
您需要更正服务器证书以具有所需的主机名(或IP地址)SAN条目。
您可以使用以下方法调试此类TLS连接错误以及其他错误:
dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
    conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
    if err != nil {
        fmt.Println(err)
    }
    return conn, err
}

我正在特定地传递以下格式的内容: -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE----- - jimmiebtlr
避免传递文件名,而是只传递一个字符串,可以通过环境变量或类似方式设置。 - jimmiebtlr
它似乎至少将正确的值传递给函数。 - jimmiebtlr
你验证过 AppendCertsFromPEM 是否返回了 true 吗?另外,重新阅读了你的帖子,你的 mongo 连接正在使用客户端证书。你是否只想接受经过身份验证的客户端?如果是这样,需要将客户端证书添加到 tlsConfig 中。 - Martin Campbell
AppendCertsFromPEM 返回 true,刚刚更新了一下 MongoDB 的配置,移除了客户端证书验证。最初尝试验证客户端证书,但后来移除了该功能(据我所知,在 compose 中无法进行配置)。 - jimmiebtlr
看了一下你的证书。你的自签名 CA 没问题,但是你的服务器证书有问题。你使用的 CN 是 127.0.01,我猜这个不会匹配服务器主机名,并且没有 SANs。你可能需要在 TLS 配置中设置 ServerName。此外,你没有任何服务器证书扩展,因此证书可能因为这个原因被拒绝。在 DialServer 函数内拨号后,err 是否包含任何错误? - Martin Campbell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接