如何配置 PostgreSQL 的 pg_hba.conf 以允许与已验证证书的连接,但如果不这样做则拒绝它们(包括本地主机)?

Has*_*ers 3 authentication postgresql openssl ssl-certificate tls1.3

我已使用 PostgreSQL 二进制文件在本地计算机上设置了 PostgreSQL (v.15) 服务器。

我已经使用此链接生成了证书。

我已将证书存储在 c:/certs 中,并将它们复制到本地 PostgreSQL 服务器的数据文件夹(与postgresql.conf文件所在的文件夹相同)。我已将postgresql.conf配置为使用 SSL 和证书,如此图所示。

当我尝试使用 psql 连接到 PostgreSQL 服务器时,我希望它仅在提供有效证书时接受我的连接尝试,例如采用以下格式:

psql 'host=localhost port=5432 dbname=local-db user=admin sslmode=verify-full sslcert=c:/certs/cert.pem sslkey=c:/certs/cert-key.pem sslrootcert=c:/certs/ca.pem'
Run Code Online (Sandbox Code Playgroud)

但我希望当我不提供证书时它拒绝我的连接尝试,例如以下格式:

psql 'host=localhost port=5432 dbname=local-db user=admin'
Run Code Online (Sandbox Code Playgroud)

我假设我需要以特定方式配置 PostgreSQL 服务器的pg_hba.conf文件(它与证书和postgresql.conf文件位于同一文件夹中),并且我已经尝试了在互联网上可以找到的所有建议,但是我一直以服务器结束,要么允许上述两种连接尝试,要么两者都不允许,但决不允许其中之一而不是另一个。

我尝试按如下方式配置pg_hba.conf:

hostnossl   all   all   0.0.0.0/0   reject
hostssl     all   all   0.0.0.0/0   cert clientcert=verify-full
Run Code Online (Sandbox Code Playgroud)

但是,对于提供证书的连接,我收到以下错误:

psql: error: connection to server at "localhost" (::1), port 5432 failed: FATAL:  no pg_hba.conf entry for host "::1", user "admin", database "local-db", SSL encryption
Run Code Online (Sandbox Code Playgroud)

对于不提供证书的连接,我收到以下两个错误:

psql: error: connection to server at "localhost" (::1), port 5432 failed: FATAL:  no pg_hba.conf entry for host "::1", user "admin", database "local-db", SSL encryption

connection to server at "localhost" (::1), port 5432 failed: FATAL:  no pg_hba.conf entry for host "::1", user "admin", database "local-db", no encryption
Run Code Online (Sandbox Code Playgroud)

我想原因是它尝试通过 IPv6 而不是 Ipv4 进行连接。当我如下配置pg_hba.conf时:

hostnossl   all   all   ::/0   reject
hostssl     all   all   ::/0   cert clientcert=verify-full
Run Code Online (Sandbox Code Playgroud)

然后它似乎阻止不提供证书的连接(根据需要):

psql: error: connection to server at "localhost" (::1), port 5432 failed: FATAL:  connection requires a valid client certificate

connection to server at "localhost" (::1), port 5432 failed: FATAL:  pg_hba.conf rejects connection for host "::1", user "admin", database "local-db", no encryption
Run Code Online (Sandbox Code Playgroud)

但对于提供证书的连接,我也收到以下错误:

psql: error: connection to server at "localhost" (::1), port 5432 failed: FATAL:  certificate authentication failed for user "admin"
Run Code Online (Sandbox Code Playgroud)

当我使用以下 CLI 命令验证证书时:openssl verify -CAfile ca.pem -verbose cert.pem. 然后它告诉我证书是“OK”,所以我不知道可能出了什么问题,但我认为它与我的pg_hba配置(和/或我的psql连接字符串)有关。

我尝试更改clientcert=verify-full为clientcert=1,因为我看到很多人在网上推荐它,但是我的 PostgreSQL 服务器拒绝再次启动(每当我更改其.conf文件时我都会重新启动它)并在其日志文件中注册以下两行:

FATAL:  could not load pg_hba.conf
LOG:  database system is shut down
Run Code Online (Sandbox Code Playgroud)

请帮助我了解如何让 PostgreSQL 服务器仅接受提供证书的连接。

Has*_*ers 5

看来我的证书设置没有正确设置。我使用此链接生成新证书(并修改 CN [通用名称] 值以匹配我的主机名 [localhost] 和用户名 [admin],如下所示):

openssl req -new -x509 -days 365 -nodes -out ca.crt -keyout ca.key -subj "/CN=root-ca"

openssl genrsa -des3 -out server.key 2048
openssl rsa -in server.key -out server.key
openssl req -new -nodes -key server.key -out server.csr -subj "/CN=localhost"
openssl x509 -req -in server.csr -days 365 -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt

openssl genrsa -des3 -out client.key 2048
openssl rsa -in client.key -out client.key
openssl req -new -nodes -key client.key -out client.csr -subj "/CN=admin"
openssl x509 -req -in client.csr -days 365 -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt
Run Code Online (Sandbox Code Playgroud)

然后我将它们复制到上述数据文件夹并修改postgresql.conf如下:

ssl = on
ssl_ca_file = 'ca.crt'
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
Run Code Online (Sandbox Code Playgroud)

在pg_hba.conf中,我只在底部设置了以下四行(其余的已注释掉):

hostnossl   all   all   0.0.0.0/0   reject
hostnossl   all   all   ::/0        reject
hostssl     all   all   0.0.0.0/0   cert clientcert=verify-full
hostssl     all   all   ::/0        cert clientcert=verify-full
Run Code Online (Sandbox Code Playgroud)

这样,它就完成了我想要的操作,即它阻止了未提供证书的连接,同时允许提供证书的连接(如下所示):

psql 'host=localhost port=5432 dbname=local-db user=admin sslmode=verify-full sslcert=c:/certs/client.crt sslkey=c:/certs/client.key sslrootcert=c:/certs/ca.crt'
Run Code Online (Sandbox Code Playgroud)

正确设置公用名是连接尝试被接受或拒绝的(最)决定因素。