简体   繁体   English

pgx tls 连接为有效证书引发客户端证书无效错误

[英]pgx tls connection throws client cert invalid error for valid cert

I'm trying to use pgx to make a TLS connection to a postgres 10 db.我正在尝试使用 pgx 与 postgres 10 db 建立 TLS 连接。

My connection string is similar to: "host='my-host.com' port='5432' dbname='my-db' user='my-db-user' sslmode='verify-full' sslcert='/path/to/db_user.crt' sslkey='/path/to/db_user.key' sslrootcert='/path/to/ca_roots.pem'"我的连接字符串类似于: "host='my-host.com' port='5432' dbname='my-db' user='my-db-user' sslmode='verify-full' sslcert='/path/to/db_user.crt' sslkey='/path/to/db_user.key' sslrootcert='/path/to/ca_roots.pem'"

When I run this directly with psql on the command-line, it works, so the cert and key files must be valid.当我在命令行上直接使用psql运行它时,它可以工作,因此证书和密钥文件必须有效。 db_user.crt and db_user.key are both PEM files. db_user.crtdb_user.key都是 PEM 文件。 (the command-line also works with sslmode='verify-full' , so the rootcert should also be ok) (命令行也适用于sslmode='verify-full' ,所以 rootcert 也应该没问题)

But when I initialize a pgx pool with that connection string, it fails with:但是,当我使用该连接字符串初始化pgx池时,它会失败并显示:

FATAL: connection requires a valid client certificate (SQLSTATE 28000)致命:连接需要有效的客户端证书 (SQLSTATE 28000)

Is go expecting something other than PEM? go 是否期待 PEM 以外的其他东西? Or is there a different way ssl cert and key pair is supposed to be initialized with pgx?或者是否有不同的方式 ssl 证书和密钥对应该用 pgx 初始化?

Code代码

import (
    "context"
    "fmt"
    "os"

    "github.com/jackc/pgx/v4"
    "github.com/jackc/pgx/v4/pgxpool"
)

type mockLogger struct{}

func (ml *mockLogger) Log(ctx context.Context, level pgx.LogLevel, msg string, data map[string]interface{}) {
    fmt.Printf("[%s] %s : %+v\n", level.String(), msg, data)
}

func connect() error {
    connStr := "host='my-host.com' port='5432' dbname='my-db' user='my-db-user' sslmode='verify-full' sslcert='/path/to/db_user.crt' sslkey='/path/to/db_user.key' sslrootcert='/path/to/ca_roots.pem'"
    poolCfg, err := pgxpool.ParseConfig(connStr)
    if err != nil {
        return err
    }
    poolCfg.ConnConfig.Logger = &mockLogger{}
    poolCfg.ConnConfig.LogLevel = pgx.LogLevelTrace
    fmt.Printf("using connection string: \"%s\"\n", poolCfg.ConnString())

    connPool, err := pgxpool.ConnectConfig(context.TODO(), poolCfg)
    if err != nil {
        return err
    }

    connPool.Close()
    return nil
}

func main() {
    if err := connect(); err != nil {
        fmt.Printf("%+v\n", err)
        os.Exit(1)
    }
}

Output from calling connect() : Output 通过调用connect()

using connection string: "host='my-host.com' port='5432' dbname='my-db' user='my-db-user' sslmode='require' sslcert='/path/to/db_user.crt' sslkey='/path/to/db_user.key' sslrootcert='/path/to/ca_roots.pem'"
[info] Dialing PostgreSQL server : map[host:my-host.com]
[error] connect failed : map[err:failed to connect to `host=my-host.com user=my-db-user database=my-db`: server error (FATAL: connection requires a valid client certificate (SQLSTATE 28000))]
failed to connect to `host=my-host.com user=my-db-user database=my-db`: server error (FATAL: connection requires a valid client certificate (SQLSTATE 28000))

Summary概括

Turns out for go, the cert pointed to by sslcert needed to contain the full client cert chain .结果是 go, sslcert指向的证书需要包含完整的客户端证书链

When /path/to/db_user.crt contained the client cert followed by client cert chain, the pgx connection worked./path/to/db_user.crt包含客户端证书后跟客户端证书链时, pgx连接有效。

Whereas the psql command worked in both cases:psql命令在这两种情况下都有效:

  • when sslcert was just the leaf client cert without the chainsslcert只是没有链的叶客户端证书时
  • when sslcert contained client cert + chainsslcert包含客户端证书 + 链时

Not sure why psql was fine without the full chain, but it works now.不知道为什么 psql 没有完整的链就很好,但它现在可以工作了。

Details细节

Under-the-hood, pgx uses the pgconn module to create the connection.在幕后,pgx 使用pgconn模块来创建连接。 That, in turn, is just calling tls.X509KeyPair on the contents of the sslcert and sslkey files.反过来,这只是在sslcertsslkey文件的内容上调用tls.X509KeyPair

pgconn/config.go : pgconn/config.go

func configTLS(settings map[string]string, thisHost string, parseConfigOptions ParseConfigOptions) ([]*tls.Config, error) {
    [...]
    sslcert := settings["sslcert"]
    sslkey := settings["sslkey"]
    [...]
    if sslcert != "" && sslkey != "" {
        [...]
        certfile, err := ioutil.ReadFile(sslcert)
        if err != nil {
            return nil, fmt.Errorf("unable to read cert: %w", err)
        }
        cert, err := tls.X509KeyPair(certfile, pemKey)
        if err != nil {
            return nil, fmt.Errorf("unable to load cert: %w", err)
        }
        tlsConfig.Certificates = []tls.Certificate{cert}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用证书身份验证的 Django 连接到 Postgresql - Django connection to Postgresql using cert authentication postgres jdbc客户端cert用户vs db用户 - postgres jdbc client cert user vs db user 如何为 Rails pg gem 构建 SSL 证书/链来修复 PG::ConnectionBad(SSL SYSCALL 错误:连接由对等方重置(0x00002746/10054)) - How can I build an SSL cert/chain for the Rails pg gem to fix PG::ConnectionBad (SSL SYSCALL error: Connection reset by peer (0x00002746/10054)) PostgreSQL 连接需要有效的客户端证书 - PostgreSQL connection require a valid client certificate psql:致命:连接需要有效的客户端证书 - psql: FATAL: connection requires a valid client certificate Azure 在哪里指定 ssl_cert_file 等? - Where to specify ssl_cert_file and alike at Azure? 查询 JSONB。 Sequelize Op.In 抛出错误:无效值 - Querying JSONB. Sequelize Op.In throws Error: Invalid value 使用node和sequelize插入到postdb时无效的有效错误 - Invalid valid error while inserting to postgress db using node and sequelize 连接需要 laravel 谷歌云 postgres 中的有效客户端证书与 ssl 模式 - connection requires a valid client certificate in laravel google cloud postgres with ssl mode 通过 R Postgres 连接到 RDS 时如何指定 ca 证书? - How do you specify the ca cert when connecting to RDS via R Postgres?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM