[英]How to connect with PostgreSQL database over SSL?
我创建了自己的证书并配置postgresql.conf
文件:
...
#authentication_timeout = 1min # 1s-600s
ssl = true # (change requires restart)
ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
# (change requires restart)
#ssl_prefer_server_ciphers = on # (change requires restart)
#ssl_ecdh_curve = 'prime256v1' # (change requires restart)
ssl_cert_file = '/etc/ssl/certs/company/database/certificate' # (change requires restart)
ssl_key_file = '/etc/ssl/certs/company/database/key' # (change requires restart)
ssl_ca_file = '/usr/share/ca-certificates/company/ca/certificate' # (change requires restart)
#ssl_crl_file = '' # (change requires restart)
#password_encryption = on
#db_user_namespace = off
#row_security = on
...
然后,我允许我的服务器连接到我的数据库pg_hba.conf
:
...
hostssl postgres postgres XXX.XXX.XXX.XXX/0 md5
...
所以,我可以通过psql
命令行连接到它:
psql (9.5.3)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
postgres=#
但是,当我尝试通过我的 java 应用程序打开与数据库的连接时,即使我提供包含我的数据库证书的信任库,我仍然无法与它建立连接:
mvn package -Djavax.net.ssl.trustStore=/opt/app/truststore -Djavax.net.ssl.trustStorePassword=changeit
例外:
2016-05-23 16:28:32,900 WARN [com.mchange.v2.resourcepool.BasicResourcePool] - <Having failed to acquire a resource, com.mchange.v2.resourcepool.BasicResourcePool@75fa1be3 is interrupting all Threads waiting on a resource to check out. Will try again in response to new client requests.>
2016-05-23 16:28:32,900 WARN [com.mchange.v2.resourcepool.BasicResourcePool] - <com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask@2be057bf -- Acquisition Attempt Failed!!! Clearing pending acquires. While trying to acquire a needed new resource, we failed to succeed more than the maximum number of allowed acquisition attempts (30). Last acquisition attempt exception: >
java.lang.NullPointerException
at org.postgresql.Driver.parseURL(Driver.java:532)
at org.postgresql.Driver.acceptsURL(Driver.java:431)
at java.sql.DriverManager.getDriver(DriverManager.java:299)
at com.mchange.v2.c3p0.DriverManagerDataSource.driver(DriverManagerDataSource.java:285)
at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:161)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:161)
at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:147)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:202)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1138)
at com.mchange.v2.resourcepool.BasicResourcePool.doAcquireAndDecrementPendingAcquiresWithinLockOnSuccess(BasicResourcePool.java:1125)
at com.mchange.v2.resourcepool.BasicResourcePool.access$700(BasicResourcePool.java:44)
at com.mchange.v2.resourcepool.BasicResourcePool$ScatteredAcquireTask.run(BasicResourcePool.java:1870)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
2016-05-23 16:28:32,901 WARN [com.mchange.v2.resourcepool.BasicResourcePool] - <Having failed to acquire a resource, com.mchange.v2.resourcepool.BasicResourcePool@75fa1be3 is interrupting all Threads waiting on a resource to check out. Will try again in response to new client requests.>
通过psql
一切似乎都工作正常,而不是我的应用程序。 有什么建议吗?
编辑:
我的props.properties
文件:
uatDb.user=postgres
uatDb.password=password
uatDb.driverClass=org.postgresql.Driver
uatDb.jdbcUrl=jdbc:postgresql://<server_name>:1234/uat?ssl=true
uatDb.port=5443
uatDb.name=uat
uatDb.host=<server_name>
url=jdbc:postgresql://<host_url_or_ip>:<port>/<db_name>?currentSchema=<schema_name>&sslmode=verify-ca&sslfactory=org.postgresql.ssl.DefaultJavaSSLFactory
注意:如果schema_name
是public
,则不需要。 但是即使端口是默认的,即 5432,你也必须提供它。
对于 sslmode 值参考: https : sslfactory=org.postgresql.ssl.DefaultJavaSSLFactory
设置sslfactory=org.postgresql.ssl.DefaultJavaSSLFactory
以启用验证。
对于非验证 ssl 连接,您可以使用sslfactory=org.postgresql.ssl.NonValidatingFactory
但请记住,一旦启用 SSL 验证,它可能需要根 CA 证书。
您有以下各种选择(可能并不详尽。但这些对我有用。)
PGSSLROOTCERT
变量设置为其路径或-Djavax.net.ssl.trustStore=[trust_store_path] -Djavax.net.ssl.trustStorePassword=[trust_store_password]
。 如果您使用默认信任库,即 JRE 的cacerts
则不需要这两个环境变量。参考:
https://jdbc.postgresql.org/documentation/head/ssl-client.html
我相信也需要一个密钥库。 由于 ssl=true 应该需要您的自签名证书的私钥。 我还会添加“nonValidating SSLFactory”设置
?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
此外,您的server_name:1234
端口设置与5432
不匹配。
"parseUrl"
是一个空错误,也许 JDBC url 中某处有一个变量设置不正确。
如果不需要验证数据库客户端,只需在postgresql.conf
注释掉ssl_ca_file
。
ssl_ca_file
- 受信任的证书颁发机构,检查客户端证书是否由受信任的证书颁发机构签名。
您的数据库 URL 应如下所示:
url=jdbc:postgresql://host:5432/db_name?ssl=true&sslmode=require
有关sslmode
更多详细信息,请参阅PostgreSQL JDBC 文档。
否则,如果您需要验证数据库客户端,您应该将sslcert=...
和sslkey=...
参数添加到您的数据库 URL。
我遇到了 jfrog 人工连接到 azure postgres 的问题,下面这个对我有用
sudo cat <<EOF >/opt/jfrog/artifactory/var/etc/system.yaml configVersion: 1 shared: node: database: type: postgresql driver: org.postgresql.Driver url: "jdbc:postgresql://test-psqlserver.postgres.database.azure.com:5432/postgres?ssl=true&sslmode=require" username: psqladminun@test-psqlserver password: password:-) EOF
https://stackoverflow.com/users/3612771/dv-santhosh-kiran在这里做一些事情。
他们的一些信息并不完全准确。 sslfactory=org.postgresql.ssl.DefaultJavaSSLFactory is good - but it relies on SSLSocketFactory.getDefault() which knows how to read CA trust stores from $JAVA_HOME/lib/security/cacerts, or from javax.net.ssl.* properties as每个答案中的第 3 点。 如果您使用默认的 sslfactory,则第 1 点和第 2 点是正确的,org.postgresql.ssl.LibPQFactory,但 100% 与 DefaultJavaSSLFactory 完全不兼容。 所以要小心。
另外,我建议选项号 4。将根 CA 添加到 JRE cacerts 文件,并让 java 执行其默认操作。 您必须为此使用 keytool,但如果在运行时 jvm 中有多个客户端,它比 java.net.ssl 设置更灵活。
keytool -importcert -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -noprompt -alias "$ALIAS" -file $YOUR_CERT -trustcacerts
请参阅https://docs.oracle.com/en/java/javase/11/tools/keytool.html和里程可能会有所不同。 您要做的是将(x509/pkix)证书导入 cacerts java 密钥库
fwiw org.postgresql.ssl.LibPQFactory 是一个糟糕的名字,让人认为 postgres 驱动程序会做一些 JNI 并调用 Z0D61F8370CAD1D412F57B84D143E1。 这不是作者的本意。 class 可能是 SslFactoryThatDoesPathsLikeLibPQBro。 这就是它对 libpq 所做的一切:像 LibPQ 一样在路径中查找证书。 除此之外,它使用常规的旧 java JSSE 为 TLS 加载信任库证书。 看看源代码: https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/ssl/LibPQFactory.java#L102
SSLContext ctx = SSLContext.getInstance("TLS");
... stuff about libpq path locations ...
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
...
ks = KeyStore.getInstance("jks");
...
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Object[] certs = cf.generateCertificates(fis).toArray(new Certificate[]{});
ks.load(null, null);
for (int i = 0; i < certs.length; i++) {
ks.setCertificateEntry("cert" + i, (Certificate) certs[i]);
}
tmf.init(ks);
tm = tmf.getTrustManagers();
...
// finally we can initialize the context
...
KeyManager km = this.km;
ctx.init(km == null ? null : new KeyManager[]{km}, tm, null);
...
factory = ctx.getSocketFactory();
对于那些使用 Springboot & SSL
将密钥从 pem 转换为 pkcs8
openssl pkcs8 -topk8 -inform PEM -outform DER \
-in client-key.pem \
-out client-key.pkcs8 -nocrypt
将证书添加到 applications.properties 中的 db url
spring.datasource.url=jdbc:postgresql://<DB_IP>/mydbName?ssl=true&sslmode=verify-ca\
&sslcert=BOOT-INF/classes/db/certs/client-cert.pem\
&sslkey=BOOT-INF/classes/db/certs/client-key.pkcs8\
&sslrootcert=BOOT-INF/classes/db/certs/server-ca.pem
嘿,如果有人找到一种方法将此证书/密钥放入 env var 并在 jdbc-url 中使用,请编辑/添加该信息。 这将更好地与 cloudnative/k8s 保持一致。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.