如何在SSL上将Google App Engine API(ASP.NET Core 3.1)连接到Google Clo



这是我从未问过的最令人沮丧的问题。我该如何连接这两个?

我有一个API(ASP.NET Core 3.1),我将这个应用程序部署到谷歌的应用程序引擎上。我还连接了一个云SQL数据库(PostgreSQL引擎12)。没有SSL,连接就可以完美地工作。添加SSL是一个巨大的痛苦。我不断地得到以下错误:

Error Connecting to database FATAL : no pg_hba.conf entry for host"x.x.x.x", user"jiradbuser", database"jiradb", SSL off

上面的错误没有任何意义,因为我在GCP上没有任何选项来修改这样的文件。

当我将数据库配置为只接受SSL连接时,我已经下载了谷歌给我的client-cert.pem、client-key.pem和server-ca.pem文件,当我在PSQL中运行以下命令时,我通过SSL进行了很好的连接:

psql "sslmode=verify-ca sslrootcert=server-ca.pem sslcert=client-cert.pem sslkey=client-key.pem hostaddr=<cloud sql public ip> port=5432 user=< my username> dbname=<database inside cloud sql instance>"

我曾尝试使用NpgSqlConnectionStringBuilder,在那里我从配置文件中获取相关的----BEGIN CERTIFICATE-------END CERTIFICATION----文件,以生成包含该信息的连接字符串,但这不起作用:

var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString)
{
RootCertificate = Configuration["Google:ServerCA"],
ClientCertificate = Configuration["Google:ClientCert"],
ClientCertificateKey = Configuration["Google:ClientKey"],
SslMode = SslMode.Require,
TrustServerCertificate = true,
IncludeErrorDetails = true
};

以下是错误消息:

"exception":{"StackTrace":"   at Interop.Crypto.CheckValidOpenSslHandle(SafeHandle handle)\n   at Internal.Cryptography.Pal.OpenSslX509CertificateReader.FromFile(String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)\n   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)\n   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password)\n   at Npgsql.NpgsqlConnector.RawOpen(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)\n   at Npgsql.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)\n   at Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)\n   at Npgsql.ConnectorPool.<>c__DisplayClass38_0.<<Rent>g__RentAsync|0>d.MoveNext()\n--- End of stack trace from previous location where exception was thrown ---

我缺了一步吗?我需要将这些文件转换为其他格式(如.pfx、.crt或.key)吗?我不认为我必须这样做,否则谷歌为什么要给我.pem文件?此外,我倾向于将文件本身存储在谷歌秘密管理器中。。。这会改变什么吗?

我愿意回答您的问题或添加适当的其他信息。谢谢

工作解决方案

在过去的24小时里,我一直在忍受同样的问题。我在下面列出了一个可行的解决方案。为第一次尝试道歉。。。那是我在大声思考,这在这些论坛上是不合适的。

该解决方案基于C#dotnet核心SDK 5.0.201控制台应用程序,该应用程序在Windows 10 Professional上运行,带有Google SQL Cloud PostgreSQL 13后端数据库。

PEM文件

Google SQL Cloud提供PEM文件;其中三个。两个证书和一个密钥。有一个服务器证书颁发机构证书(Server-ca.pem)和一个具有相应密钥的客户端证书(分别为Client-cert.pem和Client-Key.pem)。

根据您的示例,psql命令建议连接到SQL Cloud需要这三个命令。我使用的是pgAdmin,它的作用基本相同。

客户端证书和相应的密钥需要转换为PFX(个人信息交换)格式。这种文件格式基本上将客户端证书和密钥配对到一个文件中。

有两种方法可以执行此转换。。。使用CCD_ 2命令或使用C#在代码中执行。

你可以在";回答";这个StackOverflow帖子的。。。

在.net核心web api 中使用ssl证书的Npgsql连接

来源:Anish-V

如何将证书和密钥正确传递到Npgsql连接

连接字符串

首先,设置连接字符串。除了SSL证书,您还需要提供主机、数据库名称、数据库用户名和密码等信息。此外,由于我们的目标是与谷歌SQL云的SSL连接,您可能会勾选";"只允许SSL连接";标志。如果是,您还需要将SslMode设置为";要求";(或者根据您的要求/配置,可以选择"首选")。

var _connectionString = new NpgsqlConnectionStringBuilder()
{
Host = settings.Host,
Database = settings.Database,
Username = settings.Username,
Password = settings.Password,
SslMode = SslMode.Require
};
var _pgdb = new NpgsqlConnection(_connectionString.ConnectionString);

客户端证书和密钥

查看客户端证书和密钥,上面的StackOverflow帖子获取客户端证书(Client-cert.pem)和密钥(Client-key.pem),并创建一个组合的PFX证书。如上所述,您可以使用openssl或在代码中执行此操作。此刻,我正在追求";在代码"中;在将来发布应用程序时减少任何手动步骤的方法。然而,我已经测试了openssl方法,并生成了一个PFX文件。。。这也是有效的。

要将PFX证书添加到连接,请使用NpgsqlConnection类的ProvideClientCertificatesCallback方法。。。

_pgdb.ProvideClientCertificatesCallback += new ProvideClientCertificatesCallback;
_pgdb.Open();

我们现在用自己的实现重载ProvideClientCertificatesCallback方法,如下。。。

public void ProvideClientCertificatesCallback(X509CertificateCollection certificates)
{
var clientCert = 
GetCombinedCertificateAndKey(
$@"{certificatePath}client-cert.pem",
$@"{certificatePath}client-key.pem");
certificates.Add(clientCert);
Console.WritLine($"client-cert.pem/client-key.perm: {clientCert.Issuer}");
}

方法GetCombinedCertificateAndKey采用两个参数。。。客户端证书和客户端密钥的文件名。这个方法借鉴了上面提到的StackOverflow帖子。。。我轻轻地推了一下。。。

private X509Certificate2 GetCombinedCertificateAndKey(string clientCertPath, string clientKeyPath)
{
using var publicKey = new X509Certificate2(clientCertPath); ;
var privateKeyText = System.IO.File.ReadAllText(clientKeyPath);
var privateKeyBlocks = privateKeyText.Split("-", StringSplitOptions.RemoveEmptyEntries);
var privateKeyBytes = Convert.FromBase64String(privateKeyBlocks[1]);
using var rsa = RSA.Create();
switch (privateKeyBlocks[0]) {
case "BEGIN PRIVATE KEY":
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
break;
case "BEGIN RSA PRIVATE KEY":
rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
break;
}
var keyPair = publicKey.CopyWithPrivateKey(rsa);
var Certificate = new X509Certificate2(keyPair.Export(X509ContentType.Pfx));
return Certificate;
}

通过Visual Studio调试器运行它很好。。。您可以检查证书的内容。在我的例子中,Google client-key.pem似乎是一个RSA密钥,它是通过这种方法在switch语句中获取的。我怀疑所有的谷歌密钥都是一样的。

还要注意,return语句之前的行。。。它以组合PFX格式导出客户端证书/密钥对,并将其作为证书返回给调用方法。

服务器证书颁发机构证书

对于服务器CA证书,我目前的解决方案是绕过此证书的验证。为此,只需将TrustServerCertificate属性添加到连接字符串中,如下所示。顾名思义,这决定了是否信任服务器证书而不验证它。我的想法是,在这种情况下,我相信证书是由可靠的来源提供的。。。谷歌。但是,我将继续寻找一个更完整的解决方案来验证服务器CA证书。

var _connectionString = new NpgsqlConnectionStringBuilder()
{
Host = settings.Host,
Database = settings.Database,
Username = settings.Username,
Password = settings.Password,
SslMode = SslMode.Require,
TrustServerCertificate = true,
};
var _pgdb = new NpgsqlConnection(_connectionString.ConnectionString);

结论

就是这样。它有效!:-)我希望它对你有效,为你节省一天的生命。

在回答关于将证书存储在Google Secret Manager中的问题时,我建议这样做,尽管这完全是另一个话题。

最新更新