Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何通过SSL将Google应用程序引擎API(ASP.NET Core 3.1)连接到Google云SQL(Postgres)?_C#_Postgresql_Google App Engine_Google Cloud Platform_Google Cloud Sql - Fatal编程技术网

C# 如何通过SSL将Google应用程序引擎API(ASP.NET Core 3.1)连接到Google云SQL(Postgres)?

C# 如何通过SSL将Google应用程序引擎API(ASP.NET Core 3.1)连接到Google云SQL(Postgres)?,c#,postgresql,google-app-engine,google-cloud-platform,google-cloud-sql,C#,Postgresql,Google App Engine,Google Cloud Platform,Google Cloud Sql,这是我从未问过的最令人沮丧的问题。我如何连接这两者 我有一个API(ASP.NET Core 3.1),我将此应用程序部署到Google的应用程序引擎上。我还有一个连接到的云数据库SQL(PostgreSQL引擎12)。如果没有SSL,连接工作得很好。添加SSL是一个巨大的痛苦。我不断地出现以下错误: Error Connecting to database FATAL : no pg_hba.conf entry for host"x.x.x.x", user"j

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

我有一个API(ASP.NET Core 3.1),我将此应用程序部署到Google的应用程序引擎上。我还有一个连接到的云数据库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上没有任何选项来修改这样的文件

我已经下载了client-cert.pem、client-key.pem和server-ca.pem文件,当我将数据库配置为仅接受SSL连接时,Google给了我这些文件,当我在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>"
以下是错误消息:

"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 ---
“exception\”:{“StackTrace\”:“at Interop.Crypto.CheckValidOpenSslHandle(SafeHandle句柄)\\n at Internal.Cryptography.Pal.OpenSslX509CertificateReader.FromFile(字符串文件名,SafePasswordHandle密码,X509keystrageFlags keystrageFlags)\\n at System.Security.Cryptography.X509Certificates.X509Certificate(字符串文件名,字符串密码,X509KeyStrageFlags KeyStrageFlags)\\n在System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(字符串文件名,字符串密码)\\n在Npgsql.NpgsqlConnector.RawOpen(NpgsqlTimeout超时,布尔异步,CancellationToken CancellationToken)\\n在Npgsql.NpgsqlConnector.Open(NpgsqlTimeout timeout,Boolean async,CancellationToken CancellationToken)\\n位于Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn,NpgsqlTimeout timeout,Boolean async,CancellationToken CancellationToken)\\n位于Npgsql.ConnectorPool.c_udisplayClass38_0.d.MoveNext()\\n---从引发异常的前一个位置开始的堆栈结束跟踪---
是否缺少一个步骤?是否需要将这些文件转换为其他格式(例如.pfx或.crt或.key)?我不认为我必须这样做,因为否则为什么谷歌会首先给我.pem文件?此外,我倾向于将文件本身存储在Google Secret Manager中……这会改变什么吗

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

工作解决方案 在过去的24小时里,我一直在为同一个问题苦恼。我在下面列出了一个有效的解决方案。为第一次尝试表示歉意…那是我在这些论坛上大声思考的,这是不合适的

此解决方案基于一个C#dotnet core 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云需要这三个命令

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

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

你可以在这篇StackOverflow文章的“答案”中找到这两种方法

学分:

如何正确地将证书和密钥传递给Npgsql连接 连接字符串 首先,设置连接字符串。除了SSL证书外,您还需要提供主机、数据库名称、数据库用户名和密码等信息。此外,由于我们针对Google SQL Cloud的SSL连接,您可能已经勾选了“仅允许SSL连接”如果是这样,您还需要将SslMode设置为“Require”(或者根据您的需求/配置设置为“preference”)

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

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

_pgdb.ProvideClientCertificatesCallback += new ProvideClientCertificatesCallback;
_pgdb.Open();
现在,我们使用自己的实现重载
providedclientcertificatescallback
方法,如下所示

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语句中的此方法获取的。我怀疑所有Google密钥都是相同的

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

服务器证书颁发机构证书 对于服务器CA证书,我当前的解决方案是绕过此证书的验证。为此,只需将
TrustServerCertificate
属性添加到连接
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}");
}
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;
}
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);