[英]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.crt
和db_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 初始化?
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))
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
命令在这两种情况下都有效:
sslcert
was just the leaf client cert without the chainsslcert
只是没有链的叶客户端证书时sslcert
contained client cert + chainsslcert
包含客户端证书 + 链时Not sure why psql was fine without the full chain, but it works now.不知道为什么 psql 没有完整的链就很好,但它现在可以工作了。
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.反过来,这只是在
sslcert
和sslkey
文件的内容上调用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.