无法使用带有服务器 CA 验证的 TLS 连接到 AWS 数据库
Cannot Connect to AWS Database using TLS with Server CA Validation
AWS 文档指出,要连接到我的 DocumentDB 集群,我需要使用以 ?ssl_ca_certs=rds-combined-ca-bundle.pem&replicaSet=rs0
结尾的查询字符串。 It is a root certificate chain that my Client should validate. I should not need a Client Certificate.
使用 MongoDB C# 驱动程序和这个特定的查询,与同一目录中的 .pem
文件,我无法建立连接。如果我使用相同的 .pem
文件和来自 Mongo Shell 的查询字符串,我可以正确连接到我的数据库。它仅在我的 .net 核心应用程序中不起作用,该应用程序也在 AWS 上运行。
通过从集群中删除 TLS 并从查询中删除 ssl_ca_certs
选项,我可以正确连接到我的集群。
我想我可以使用 openssl
将 .pem
文件转换为 .pfx
,但我必须给 .pfx
密码和 MongoDB documentation states that
It is imperative that when loading a certificate with a password, the
PrivateKey property not be null. If the property is null, it means
that your certificate does not contain the private key and will not be
passed to the server.
如何使用 the .pem
file provided by Amazon AWS 通过 C# MongoDB 驱动程序连接到我的数据库?
尝试将 RDS CA 文件添加到您的 C# 信任库中。
X509Store store = new X509Store(StoreName.Root);
X509Certificate2 ca = new X509Certificate2(<path_to_rds-combined-ca-bundle.pem>);
try {
store.Open(OpenFlags.ReadWrite);
store.Add(ca);
} catch (Exception ex) {
Console.WriteLine("Root certificate import failed: " + ex.Message);
throw;
} finally {
store.Close();
}
###使用带有 SSL 的简单 .Net 控制台应用程序连接到文档数据库。
->首先,通过将参数 tls 设置为 'enabled',在您的文档数据库集群上启用 SSL。确保重启集群的写入器节点以重启整个集群,以便应用参数组更改。默认情况下启用 TLS 启动新的 Doc DB 集群。
->在您的环境中设置 SSL 证书:
1)从下面 link:
下载源 windows 机器上的 PKCS#7 SSL 证书
https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.p7b
2)点击开始菜单,点击运行并输入mmc
3)在MMC中,文件->Add/Remove管理单元。
4)Select 管理单元列表中的证书并单击添加。
5) 受信任的 CA 证书应该在本地计算机存储中,因此选择 'Computer Account' 单选按钮,单击下一步,然后选择“本地计算机”。单击下一步,然后单击完成。
6)现在在左侧窗格中(在 Console Root 下,您将看到“证书”选项。单击它。
7)将出现一个列表,右键单击“受信任的根证书颁发机构”,然后选择所有任务->导入
8) 在打开的 window 中,单击下一步,浏览在步骤 1 中下载的证书 (.p7b) 文件(如果找不到,请从文件类型下拉列表中, select 所有文件),然后继续单击下一步,最后单击完成。然后保存配置。
->然后写了下面的代码:
---------------------------------------------------
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace FirstDocDB
{
public class Program
{
public static void Main(string[] args)
{
var connectionString = "mongodb://pulkit:password@ClusterID:27017/?ssl=true&sslVerifyCertificate=true&replicaSet=rs0";
var client = new MongoClient(connectionString);
var database = client.GetDatabase("test");
var collection = database.GetCollection("stuff");
var document = collection.Find(new BsonDocument()).FirstOrDefault();
Console.WriteLine(document.ToString());
}
}
}
---------------------------------------------------
->在构建和 运行 之后,我成功地获得了名为“stuff”的集合中的文档作为输出:
{ “_id”:ObjectId(“5c5a63b10cf861158c1d241c”),"hello":"world"}
因此,在执行上述步骤后,我可以使用 Mongo .Net 驱动程序成功连接到文档数据库。
我遇到了类似的问题,在 AWS 上开了一张工单,并通过与 Pulkit Agarwal 的回答类似的步骤解决了这个问题。
主要变化是连接字符串,即使在将证书添加到本地存储后我仍然使用查询字符串作为“?ssl_ca_certs=rds-combined-ca-bundle.pem&replicaSet=rs0”需要更改为“?ssl=true&sslVerifyCertificate=true&replicaSet=rs0”
这是另一种方法。但是,我发现通过将 SSL 与 C# Mongo 驱动程序一起使用,不会进行连接池化并为每次调用打开一个新连接。您可以通过包含 MaxConnectionIdleTime 来减少活动连接,但如果您的应用程序创建大量连接,它仍然不理想。
var connectionString = "username:password@cluster_endpoint:27017/?replicaSet=rs0";
var clientSettings = MongoClientSettings.FromUrl(new MongoUrl("mongodb://" + connectionString));
var certificatePath = "ssl\rds-combined-ca-bundle.pem";
var pem = System.IO.File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + certificatePath);
byte[] certBuffer = GetBytesFromPEM(pem, "CERTIFICATE");
clientSettings.UseSsl = true;
clientSettings.SslSettings = new SslSettings()
{
ClientCertificates = new List<X509Certificate2>()
{
new X509Certificate2(certBuffer)
},
EnabledSslProtocols = System.Security.Authentication.SslProtocols.Default,
CheckCertificateRevocation = true
};
clientSettings.VerifySslCertificate = true;
clientSettings.SslSettings.ClientCertificateSelectionCallback = (sender, host, certificates, certificate, issuers) => clientSettings.SslSettings.ClientCertificates.ToList()[0];
clientSettings.SslSettings.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
clientSettings.MaxConnectionIdleTime = new TimeSpan(0, 0, 30);
_client = new MongoClient(clientSettings);
_database = _client.GetDatabase(db.ToString());
以下是有关如何使用 C#(和其他驱动程序)以编程方式连接到 Amazon DocumentDB 和两个 TLS 的示例 enabled/disabled。
https://docs.aws.amazon.com/documentdb/latest/developerguide/connect.html
值得补充的是,目前,MongoDB C# 驱动程序不支持 PEM
证书。所以任何引用 PEM
证书的东西都会失败 System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
AWS Developer Guide suggests using P7B
certificates instead which can be downloaded from here: https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.p7b
这对我们有用。
在 Kubernetes 和 Windows 上,我们需要将 rds-combined-ca-bundlee.p7b
添加到本地信任库,如 AWS C# example 所示,并且不要在连接字符串中引用它。
在 Mac,由于 access denied
问题,我一直在努力以编程方式将 P7B
证书添加到密钥库。如果我设法解决它,将更新答案。
最后值得一提的是,Kenny Dickie 提供的答案基本上关闭了证书验证并使设置不安全。这行代码 clientSettings.SslSettings.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
将始终 return true
.
AWS 文档指出,要连接到我的 DocumentDB 集群,我需要使用以 ?ssl_ca_certs=rds-combined-ca-bundle.pem&replicaSet=rs0
结尾的查询字符串。 It is a root certificate chain that my Client should validate. I should not need a Client Certificate.
使用 MongoDB C# 驱动程序和这个特定的查询,与同一目录中的 .pem
文件,我无法建立连接。如果我使用相同的 .pem
文件和来自 Mongo Shell 的查询字符串,我可以正确连接到我的数据库。它仅在我的 .net 核心应用程序中不起作用,该应用程序也在 AWS 上运行。
通过从集群中删除 TLS 并从查询中删除 ssl_ca_certs
选项,我可以正确连接到我的集群。
我想我可以使用 openssl
将 .pem
文件转换为 .pfx
,但我必须给 .pfx
密码和 MongoDB documentation states that
It is imperative that when loading a certificate with a password, the PrivateKey property not be null. If the property is null, it means that your certificate does not contain the private key and will not be passed to the server.
如何使用 the .pem
file provided by Amazon AWS 通过 C# MongoDB 驱动程序连接到我的数据库?
尝试将 RDS CA 文件添加到您的 C# 信任库中。
X509Store store = new X509Store(StoreName.Root);
X509Certificate2 ca = new X509Certificate2(<path_to_rds-combined-ca-bundle.pem>);
try {
store.Open(OpenFlags.ReadWrite);
store.Add(ca);
} catch (Exception ex) {
Console.WriteLine("Root certificate import failed: " + ex.Message);
throw;
} finally {
store.Close();
}
###使用带有 SSL 的简单 .Net 控制台应用程序连接到文档数据库。
->首先,通过将参数 tls 设置为 'enabled',在您的文档数据库集群上启用 SSL。确保重启集群的写入器节点以重启整个集群,以便应用参数组更改。默认情况下启用 TLS 启动新的 Doc DB 集群。
->在您的环境中设置 SSL 证书:
1)从下面 link:
下载源 windows 机器上的 PKCS#7 SSL 证书https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.p7b
2)点击开始菜单,点击运行并输入mmc
3)在MMC中,文件->Add/Remove管理单元。
4)Select 管理单元列表中的证书并单击添加。
5) 受信任的 CA 证书应该在本地计算机存储中,因此选择 'Computer Account' 单选按钮,单击下一步,然后选择“本地计算机”。单击下一步,然后单击完成。
6)现在在左侧窗格中(在 Console Root 下,您将看到“证书”选项。单击它。
7)将出现一个列表,右键单击“受信任的根证书颁发机构”,然后选择所有任务->导入
8) 在打开的 window 中,单击下一步,浏览在步骤 1 中下载的证书 (.p7b) 文件(如果找不到,请从文件类型下拉列表中, select 所有文件),然后继续单击下一步,最后单击完成。然后保存配置。
->然后写了下面的代码:
---------------------------------------------------
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace FirstDocDB
{
public class Program
{
public static void Main(string[] args)
{
var connectionString = "mongodb://pulkit:password@ClusterID:27017/?ssl=true&sslVerifyCertificate=true&replicaSet=rs0";
var client = new MongoClient(connectionString);
var database = client.GetDatabase("test");
var collection = database.GetCollection("stuff");
var document = collection.Find(new BsonDocument()).FirstOrDefault();
Console.WriteLine(document.ToString());
}
}
}
---------------------------------------------------
->在构建和 运行 之后,我成功地获得了名为“stuff”的集合中的文档作为输出: { “_id”:ObjectId(“5c5a63b10cf861158c1d241c”),"hello":"world"}
因此,在执行上述步骤后,我可以使用 Mongo .Net 驱动程序成功连接到文档数据库。
我遇到了类似的问题,在 AWS 上开了一张工单,并通过与 Pulkit Agarwal 的回答类似的步骤解决了这个问题。
主要变化是连接字符串,即使在将证书添加到本地存储后我仍然使用查询字符串作为“?ssl_ca_certs=rds-combined-ca-bundle.pem&replicaSet=rs0”需要更改为“?ssl=true&sslVerifyCertificate=true&replicaSet=rs0”
这是另一种方法。但是,我发现通过将 SSL 与 C# Mongo 驱动程序一起使用,不会进行连接池化并为每次调用打开一个新连接。您可以通过包含 MaxConnectionIdleTime 来减少活动连接,但如果您的应用程序创建大量连接,它仍然不理想。
var connectionString = "username:password@cluster_endpoint:27017/?replicaSet=rs0";
var clientSettings = MongoClientSettings.FromUrl(new MongoUrl("mongodb://" + connectionString));
var certificatePath = "ssl\rds-combined-ca-bundle.pem";
var pem = System.IO.File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + certificatePath);
byte[] certBuffer = GetBytesFromPEM(pem, "CERTIFICATE");
clientSettings.UseSsl = true;
clientSettings.SslSettings = new SslSettings()
{
ClientCertificates = new List<X509Certificate2>()
{
new X509Certificate2(certBuffer)
},
EnabledSslProtocols = System.Security.Authentication.SslProtocols.Default,
CheckCertificateRevocation = true
};
clientSettings.VerifySslCertificate = true;
clientSettings.SslSettings.ClientCertificateSelectionCallback = (sender, host, certificates, certificate, issuers) => clientSettings.SslSettings.ClientCertificates.ToList()[0];
clientSettings.SslSettings.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
clientSettings.MaxConnectionIdleTime = new TimeSpan(0, 0, 30);
_client = new MongoClient(clientSettings);
_database = _client.GetDatabase(db.ToString());
以下是有关如何使用 C#(和其他驱动程序)以编程方式连接到 Amazon DocumentDB 和两个 TLS 的示例 enabled/disabled。
https://docs.aws.amazon.com/documentdb/latest/developerguide/connect.html
值得补充的是,目前,MongoDB C# 驱动程序不支持 PEM
证书。所以任何引用 PEM
证书的东西都会失败 System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
AWS Developer Guide suggests using P7B
certificates instead which can be downloaded from here: https://s3.amazonaws.com/rds-downloads/rds-combined-ca-bundle.p7b
这对我们有用。
在 Kubernetes 和 Windows 上,我们需要将 rds-combined-ca-bundlee.p7b
添加到本地信任库,如 AWS C# example 所示,并且不要在连接字符串中引用它。
在 Mac,由于 access denied
问题,我一直在努力以编程方式将 P7B
证书添加到密钥库。如果我设法解决它,将更新答案。
最后值得一提的是,Kenny Dickie 提供的答案基本上关闭了证书验证并使设置不安全。这行代码 clientSettings.SslSettings.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
将始终 return true
.