连接golang的mgo到MongoDB通过SSL

huangapple go评论104阅读模式
英文:

Connecting golang mgo to mongo via ssl

问题

我正在尝试在本地设置MongoDB以测试在https://www.compose.com/articles/connect-to-mongo-3-2-on-compose-from-golang/中描述的设置的部分"A Little Harder"。

MongoDB

我有一组可用的自签名凭据和MongoDB设置。我已经包含了密钥,因为这些密钥只会在开发过程中使用,以确保MongoDB 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
    }

    // 这里是session。从这里开始你可以自行处理 ;)
    session, err := mgo.DialWithInfo(dialInfo)
    if err != nil {
        return m, err
    }

    session.SetMode(mgo.Monotonic, true)

    return session, nil
}

结果

Golang部分尝试连接并达到了10秒的超时时间。在session的顶部使用fmt打印显示正确的文件已经传入了ca变量。

MongoDB日志显示:

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)

编辑
更新了MongoDB配置

英文:

I'm trying to setup mongo locally to test the setup described in

https://www.compose.com/articles/connect-to-mongo-3-2-on-compose-from-golang/
"A Little Harder" section

Mongo

I have a working set of self signed credentials, and mongo setup.
I've included keys, as those will only be used during dev to make sure mongo ssl code is working.

mongo ssl config

When using this, running via

mongod --config config/location

The config is

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

I can then connect to the db with

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
}

Result

The golang stuff tries to connect and hits the 10s timeout. A fmt at the top of session shows the correct file is making it into the ca var.

Mongo logs show

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)

Edit
Updated mongo config

答案1

得分: 3

你将什么作为NewSessionca参数传递?这应该是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
}
英文:

What are you passing into NewSession as the ca parameter? This needs to be the PEM encoded CA certificate bytes, not the file name of the CA certificate. AppendCertsFromPEM will return true if it managed to add any certificates to the pool.

The article already shows code to do this:

if ca, err := ioutil.ReadFile("myPEM"); err == nil { 
    roots.AppendCertsFromPEM(ca)
}

The SSL error means that the client is rejecting the server certificate. I suspect it is because your self-signed certificate was not added to the pool correctly.

EDIT

I ran a copy of mongo locally with your config. Using docker, this was:

docker run --rm -ti -v $(pwd):/data/mongo --net=host mongo -f /data/mongo/mongo.yaml

When ran from where your configuration was extracted

Using your NewSession func inside Go showed that the tls.Dial was returning an error due to the lack of any Subject Access Name (SAN) extensions as per my comment below.

You will need to correct your server certificate to have the appropriate host name (or IP address) SAN entries required.

You can debug this and any other TLS connection errors that occur with:

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
}

huangapple
  • 本文由 发表于 2017年7月27日 16:16:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/45345006.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定