在 mongodump 4.2+ (go lang) 中修补 SSL 证书处理
Patch SSL Certificate handling in mongodump 4.2+ (go lang)
我希望将我的 Mongo 数据库从版本 4 升级到版本 5。我使用带有 Mongo 的 ssl 配置来确保与数据库的通信是加密的。要备份数据库,我使用 mongodump。
在 Mongo 4.2 mongodump
中用 Go lang 重写,导致它在 ssl 证书处理方面导入一个常见的 Go 错误。特别是带有中间证书的 PEM 文件没有完全加载。该错误不会影响 Mongo 服务器或客户端本身、任何版本或任何其他应用程序。只有 mongodump 受到影响。
错误描述如下:https://jira.mongodb.org/browse/TOOLS-2598
Since tool's SSL/TLS code is copied from Go driver, the current implementation only parses the last certificate inside the pem file
This is a discrepancy with Mongoshell behavior, which only loads the first certificate inside the pem file.
在此相关交流中:https://jira.mongodb.org/browse/TOOLS-2996我没有看到解决方案。我已经尝试了传递给 mongodump 的参数中密钥和证书的所有排列。
I've been looking at the source code for mongodump and specifically the SSL loading code.
为了帮助 go 开发,我创建了这个 dockerfile 以立即提供一个用于构建此代码的工作环境,但我不熟悉 go 作为一种语言。
FROM centos:8
RUN yum -y update
RUN yum -y install git-core vim-enhanced golang krb5-devel krb5-libs snappy
RUN groupadd -r app -g 1000 && \
useradd -r -g app -u 1000 app -d /app && \
mkdir -p /app && \
chown -R app:app /app
USER 1000
WORKDIR /app
ENTRYPOINT /bin/bash
修复此代码库中的这些 PEM 加载错误的可能性如何?我的 Mongo 庄园有很多客户,因此轮换证书以解决此问题涉及高度的规划和停机时间。修补 mongodump 以接受现有证书感觉像是一个可以接受的中期权衡。
有没有人能帮我写合适的补丁,也许有开发人员现在使用的标准 ssl 代码?请问有人对我如何推进这件事有任何想法吗? (最好有补丁!)
由于我要测试的证书的创建方式很复杂,我在这里没有可重现的测试用例,我提前道歉。
我编写的这个补丁(基于被拒绝的 git GODRIVER-1753 拉取请求)解决了这些问题。
https://jira.mongodb.org/browse/GODRIVER-1753
https://github.com/mongodb/mongo-go-driver/pull/521/files
它还修复了 asn1 尾随数据问题。
diff --git a/README.md b/README.md
index 20f3ffe8..4b3bed1a 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,13 @@
+
+** PATCHED MONGO-TOOLS **
+
+In Mongo 4.2, the mongo team rewrote many of their core tools in Go.
+
+This introduced a bug with the way that PEM files are handled.
+Faced with downtime and complexity in a large Mongo estate, this
+patched version of mongo resolves the issues.
+
+
MongoDB Tools
===================================
diff --git a/common/db/db.go b/common/db/db.go
index 3e78abab..9290bb31 100644
--- a/common/db/db.go
+++ b/common/db/db.go
@@ -186,9 +186,13 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
}
if currentBlock.Type == "CERTIFICATE" {
- certBlock = data[start : len(data)-len(remaining)]
- certDecodedBlock = currentBlock.Bytes
- start += len(certBlock)
+ tempCertBlock := data[start : len(data)-len(remaining)]
+ certBlock = append(certBlock, tempCertBlock...) //To handle usecase where multiple certs are present
+
+ tempCertEncodedBlock := currentBlock.Bytes
+ certDecodedBlock = append(certDecodedBlock, tempCertEncodedBlock...)
+
+ start += len(tempCertBlock)
} else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") {
isEncrypted := x509.IsEncryptedPEMBlock(currentBlock) || strings.Contains(currentBlock.Type, "ENCRYPTED PRIVATE KEY")
if isEncrypted {
@@ -244,12 +248,17 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
// The documentation for the tls.X509KeyPair indicates that the Leaf certificate is not
// retained.
- crt, err := x509.ParseCertificate(certDecodedBlock)
- if err != nil {
- return "", err
- }
-
- return crt.Subject.String(), nil
+ l := len(certDecodedBlock)
+ for {
+ crt, err := x509.ParseCertificate(certDecodedBlock[0:l])
+ if err == nil {
+ return crt.Subject.String(), nil
+ }
+ l = l - 1
+ if l == 0 {
+ return "", err
+ }
+ }
}
// create a username for x509 authentication from an x509 certificate subject.
diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go
index d66114fa..2f3c6554 100644
--- a/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go
+++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go
@@ -941,9 +941,13 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
}
if currentBlock.Type == "CERTIFICATE" {
- certBlock = data[start : len(data)-len(remaining)]
- certDecodedBlock = currentBlock.Bytes
- start += len(certBlock)
+ tempCertBlock := data[start : len(data)-len(remaining)]
+ certBlock = append(certBlock, tempCertBlock...) //To handle usecase where multiple certs are present
+
+ tempCertEncodedBlock := currentBlock.Bytes
+ certDecodedBlock = append(certDecodedBlock, tempCertEncodedBlock...)
+
+ start += len(tempCertBlock)
} else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") {
isEncrypted := x509.IsEncryptedPEMBlock(currentBlock) || strings.Contains(currentBlock.Type, "ENCRYPTED PRIVATE KEY")
if isEncrypted {
@@ -997,12 +1001,18 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
// The documentation for the tls.X509KeyPair indicates that the Leaf certificate is not
// retained.
- crt, err := x509.ParseCertificate(certDecodedBlock)
- if err != nil {
- return "", err
- }
+ l := len(certDecodedBlock)
+ for {
+ crt, err := x509.ParseCertificate(certDecodedBlock[0:l])
+ if err == nil {
+ return crt.Subject.String(), nil
+ }
+ l = l - 1
+ if l == 0 {
+ return "", err
+ }
+ }
- return x509CertSubject(crt), nil
}
func stringSliceContains(source []string, target string) bool {
我希望将我的 Mongo 数据库从版本 4 升级到版本 5。我使用带有 Mongo 的 ssl 配置来确保与数据库的通信是加密的。要备份数据库,我使用 mongodump。
在 Mongo 4.2 mongodump
中用 Go lang 重写,导致它在 ssl 证书处理方面导入一个常见的 Go 错误。特别是带有中间证书的 PEM 文件没有完全加载。该错误不会影响 Mongo 服务器或客户端本身、任何版本或任何其他应用程序。只有 mongodump 受到影响。
错误描述如下:https://jira.mongodb.org/browse/TOOLS-2598
Since tool's SSL/TLS code is copied from Go driver, the current implementation only parses the last certificate inside the pem file
This is a discrepancy with Mongoshell behavior, which only loads the first certificate inside the pem file.
在此相关交流中:https://jira.mongodb.org/browse/TOOLS-2996我没有看到解决方案。我已经尝试了传递给 mongodump 的参数中密钥和证书的所有排列。
I've been looking at the source code for mongodump and specifically the SSL loading code.
为了帮助 go 开发,我创建了这个 dockerfile 以立即提供一个用于构建此代码的工作环境,但我不熟悉 go 作为一种语言。
FROM centos:8
RUN yum -y update
RUN yum -y install git-core vim-enhanced golang krb5-devel krb5-libs snappy
RUN groupadd -r app -g 1000 && \
useradd -r -g app -u 1000 app -d /app && \
mkdir -p /app && \
chown -R app:app /app
USER 1000
WORKDIR /app
ENTRYPOINT /bin/bash
修复此代码库中的这些 PEM 加载错误的可能性如何?我的 Mongo 庄园有很多客户,因此轮换证书以解决此问题涉及高度的规划和停机时间。修补 mongodump 以接受现有证书感觉像是一个可以接受的中期权衡。
有没有人能帮我写合适的补丁,也许有开发人员现在使用的标准 ssl 代码?请问有人对我如何推进这件事有任何想法吗? (最好有补丁!)
由于我要测试的证书的创建方式很复杂,我在这里没有可重现的测试用例,我提前道歉。
我编写的这个补丁(基于被拒绝的 git GODRIVER-1753 拉取请求)解决了这些问题。
https://jira.mongodb.org/browse/GODRIVER-1753
https://github.com/mongodb/mongo-go-driver/pull/521/files
它还修复了 asn1 尾随数据问题。
diff --git a/README.md b/README.md
index 20f3ffe8..4b3bed1a 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,13 @@
+
+** PATCHED MONGO-TOOLS **
+
+In Mongo 4.2, the mongo team rewrote many of their core tools in Go.
+
+This introduced a bug with the way that PEM files are handled.
+Faced with downtime and complexity in a large Mongo estate, this
+patched version of mongo resolves the issues.
+
+
MongoDB Tools
===================================
diff --git a/common/db/db.go b/common/db/db.go
index 3e78abab..9290bb31 100644
--- a/common/db/db.go
+++ b/common/db/db.go
@@ -186,9 +186,13 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
}
if currentBlock.Type == "CERTIFICATE" {
- certBlock = data[start : len(data)-len(remaining)]
- certDecodedBlock = currentBlock.Bytes
- start += len(certBlock)
+ tempCertBlock := data[start : len(data)-len(remaining)]
+ certBlock = append(certBlock, tempCertBlock...) //To handle usecase where multiple certs are present
+
+ tempCertEncodedBlock := currentBlock.Bytes
+ certDecodedBlock = append(certDecodedBlock, tempCertEncodedBlock...)
+
+ start += len(tempCertBlock)
} else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") {
isEncrypted := x509.IsEncryptedPEMBlock(currentBlock) || strings.Contains(currentBlock.Type, "ENCRYPTED PRIVATE KEY")
if isEncrypted {
@@ -244,12 +248,17 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
// The documentation for the tls.X509KeyPair indicates that the Leaf certificate is not
// retained.
- crt, err := x509.ParseCertificate(certDecodedBlock)
- if err != nil {
- return "", err
- }
-
- return crt.Subject.String(), nil
+ l := len(certDecodedBlock)
+ for {
+ crt, err := x509.ParseCertificate(certDecodedBlock[0:l])
+ if err == nil {
+ return crt.Subject.String(), nil
+ }
+ l = l - 1
+ if l == 0 {
+ return "", err
+ }
+ }
}
// create a username for x509 authentication from an x509 certificate subject.
diff --git a/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go b/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go
index d66114fa..2f3c6554 100644
--- a/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go
+++ b/vendor/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go
@@ -941,9 +941,13 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
}
if currentBlock.Type == "CERTIFICATE" {
- certBlock = data[start : len(data)-len(remaining)]
- certDecodedBlock = currentBlock.Bytes
- start += len(certBlock)
+ tempCertBlock := data[start : len(data)-len(remaining)]
+ certBlock = append(certBlock, tempCertBlock...) //To handle usecase where multiple certs are present
+
+ tempCertEncodedBlock := currentBlock.Bytes
+ certDecodedBlock = append(certDecodedBlock, tempCertEncodedBlock...)
+
+ start += len(tempCertBlock)
} else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") {
isEncrypted := x509.IsEncryptedPEMBlock(currentBlock) || strings.Contains(currentBlock.Type, "ENCRYPTED PRIVATE KEY")
if isEncrypted {
@@ -997,12 +1001,18 @@ func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (str
// The documentation for the tls.X509KeyPair indicates that the Leaf certificate is not
// retained.
- crt, err := x509.ParseCertificate(certDecodedBlock)
- if err != nil {
- return "", err
- }
+ l := len(certDecodedBlock)
+ for {
+ crt, err := x509.ParseCertificate(certDecodedBlock[0:l])
+ if err == nil {
+ return crt.Subject.String(), nil
+ }
+ l = l - 1
+ if l == 0 {
+ return "", err
+ }
+ }
- return x509CertSubject(crt), nil
}
func stringSliceContains(source []string, target string) bool {