---
title: Spring BootでPostgreSQL R2DBC DriverのTLS接続を使うメモ
tags: ["Spring WebFlux", "Spring Boot", "Java", "TLS", "R2DBC", "PostgreSQL", "Cloud Native Buildpacks", "Paketo"]
categories: ["Programming", "Java", "io", "r2dbc", "postgresql"]
date: 2021-04-18T15:35:20Z
updated: 2021-04-18T15:36:27Z
---

**目次**
<!-- toc -->

Production環境でデータベースにTLS接続しないのは許されないです。<br>[PostgreSQL R2DBC Driver](https://github.com/pgjdbc/r2dbc-postgresql) でTLS接続するときのメモ。

基本的に`spring.r2dbc.properties.sslMode`に次のいずれかの値を設定します。

* `REQUIRE` ... 通信の暗号化のみ行い、サーバーの証明は行わない
* `VERIFY_CA` ... `REQUIRE`に加え、サーバーが信頼されているかどうかチェックするがhostnameはチェックしない
* `VERIFY_FULL` ... `VERIFY_CA`に加え、hostnameのチェックも行う

`REQUIRE` < `VERIFY_CA` < `VERIFY_FULL`の順で安全な接続になります。

JavaのTrustStoreに登録されていないCAに関しては`spring.r2dbc.properties.sslRootCert`で証明書(PEMファイル)へのパスを指定できます。

`spring.r2dbc.url=r2dbc:postgresql://hostname:5432/demo?sslMode=****&sslRootCert=****`のようにURLの末尾にパラメータを指定することもできます。

実際のアプリを使って試してみます。
https://github.com/making/demo-r2dbc
のDocker Image`ghcr.io/making/demo-r2dbc`を使用します。

### 自己署名証明書の作成

`certs`ディレクトリを作成し、次の`generate-certs.sh`を作成します。

```sh
#!/bin/bash
set -ex

cd /certs
openssl req -new -nodes -out root.csr \
 -keyout root.key -subj "/CN=sslip.io"
chmod og-rwx root.key

openssl x509 -req -in root.csr -days 3650 \
 -extfile /etc/ssl/openssl.cnf -extensions v3_ca \
 -signkey root.key -out root.crt

openssl req -new -nodes -out server.csr \
 -keyout server.key -subj "/CN=*.sslip.io"
chmod og-rwx server.key

openssl x509 -req -in server.csr -days 3650 \
 -CA root.crt -CAkey root.key -CAcreateserial \
 -out server.crt
```

`certs`ディレクトリの上の階層で次のコマンドを実行して自己署名証明書を作成します。

```
docker run --rm \
 -v ${PWD}/certs:/certs \
 gcr.io/paketo-buildpacks/run:base-cnb \
 sh /certs/generate-certs.sh
```

### PostgreSQLの起動

PostgreSQLはDockerを使って次のように起動します。

```
docker run --rm \
 -p 5432:5432 \
 -e POSTGRES_DB=demo \
 -e POSTGRES_USER=demo \
 -e POSTGRES_PASSWORD=demo \
 -e POSTGRESQL_ENABLE_TLS=yes \
 -e POSTGRESQL_TLS_CERT_FILE=/certs/server.crt \
 -e POSTGRESQL_TLS_KEY_FILE=/certs/server.key \
 -e POSTGRESQL_TLS_CA_FILE=/certs/root.crt \
 -e POSTGRESQL_PGHBA_REMOVE_FILTERS=hostssl \
 -v ${PWD}/certs:/certs \
 bitnami/postgresql:11.11.0-debian-10-r59
```

### TLSを使用しない場合

まずはTLSを使用せずplaintextで接続します。
PostgreSQLはDockerのhost側で5432ポートでリッスンしているので、アプリのDockerコンテナ側から見たPostgreSQLのhostnameは`docker.host.internal`になります。

```
docker run \
  --rm \
  -m 512m \
  -p 8080:8080 \
  -e SPRING_R2DBC_URL="r2dbc:postgresql://host.docker.internal:5432/demo" \
  ghcr.io/making/demo-r2dbc 
```


`sslMode`を指定しなければ、次のログのようにplaintextで普通に接続できます。

```
Setting Active Processor Count to 4
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 512M, Thread Count: 50, Loaded Class Count: 14180, Headroom: 0%)
Adding 129 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.5)

2021-04-18 15:12:42.627  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Starting DemoR2dbcApplication v0.0.1-SNAPSHOT using Java 11.0.10 on dda341fc71a0 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2021-04-18 15:12:42.631  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : No active profile set, falling back to default profiles: default
2021-04-18 15:12:43.454  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-04-18 15:12:43.465  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 0 R2DBC repository interfaces.
2021-04-18 15:12:45.110  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-04-18 15:12:45.412  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
2021-04-18 15:12:45.428  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Started DemoR2dbcApplication in 3.38 seconds (JVM running for 3.895)
```

### sslMode=REQUIREの場合

次に`sslMode=REQUIRE`を設定して通信を暗号化します。

```
docker run \
  --rm \
  -m 512m \
  -p 8080:8080 \
  -e SPRING_R2DBC_URL="r2dbc:postgresql://host.docker.internal:5432/demo?sslMode=REQUIRE" \
  ghcr.io/making/demo-r2dbc 
```

PostgreSQL側がTLSに対応していれば、こちらも次のログのようにPostgreSQLに接続できます。信頼されたサーバーかどうかの検証は行わないので自己署名証明書でも問題ありません。

```
Setting Active Processor Count to 4
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 512M, Thread Count: 50, Loaded Class Count: 14180, Headroom: 0%)
Adding 129 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.5)

2021-04-18 15:13:17.367  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Starting DemoR2dbcApplication v0.0.1-SNAPSHOT using Java 11.0.10 on 2463512e041a with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2021-04-18 15:13:17.372  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : No active profile set, falling back to default profiles: default
2021-04-18 15:13:18.191  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-04-18 15:13:18.203  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 0 R2DBC repository interfaces.
2021-04-18 15:13:20.294  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-04-18 15:13:20.569  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
2021-04-18 15:13:20.587  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Started DemoR2dbcApplication in 3.834 seconds (JVM running for 4.363)
```

### sslMode=VERIFY_CAの場合

次に`sslMode=VERIFY_CA`を設定して通信を暗号化します。

```
docker run \
  --rm \
  -m 512m \
  -p 8080:8080 \
  -e SPRING_R2DBC_URL="r2dbc:postgresql://host.docker.internal:5432/demo?sslMode=VERIFY_CA" \
  ghcr.io/making/demo-r2dbc 
```

PostgreSQLサーバーは自己署名証明書を使用しており、信頼されたサーバーではないので次のログのように`unable to find valid certification path to requested target`というエラーメッセージがに出力されます。

```
Setting Active Processor Count to 4
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 512M, Thread Count: 50, Loaded Class Count: 14180, Headroom: 0%)
Adding 129 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.5)

2021-04-18 15:13:40.832  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Starting DemoR2dbcApplication v0.0.1-SNAPSHOT using Java 11.0.10 on f9b4293c3462 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2021-04-18 15:13:40.836  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : No active profile set, falling back to default profiles: default
2021-04-18 15:13:41.707  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-04-18 15:13:41.721  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 8 ms. Found 0 R2DBC repository interfaces.
2021-04-18 15:13:43.363 ERROR 1 --- [tor-tcp-epoll-1] reactor.core.publisher.Operators         : Operator called default onErrorDropped

io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478) ~[netty-codec-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) ~[netty-codec-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:795) ~[netty-transport-native-epoll-4.1.63.Final-linux-x86_64.jar:4.1.63.Final]
	at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480) ~[netty-transport-native-epoll-4.1.63.Final-linux-x86_64.jar:4.1.63.Final]
	at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378) ~[netty-transport-native-epoll-4.1.63.Final-linux-x86_64.jar:4.1.63.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.SSLHandshake.consume(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.HandshakeContext.dispatch(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(Unknown Source) ~[na:na]
	at java.base/java.security.AccessController.doPrivileged(Native Method) ~[na:na]
	at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(Unknown Source) ~[na:na]
	at io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1528) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1542) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1426) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1253) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1300) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508) ~[netty-codec-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447) ~[netty-codec-4.1.63.Final.jar:4.1.63.Final]
	... 15 common frames omitted
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.validator.PKIXValidator.doBuild(Unknown Source) ~[na:na]
	at java.base/sun.security.validator.PKIXValidator.engineValidate(Unknown Source) ~[na:na]
	at java.base/sun.security.validator.Validator.validate(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source) ~[na:na]
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) ~[na:na]
	... 31 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source) ~[na:na]
	at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source) ~[na:na]
	at java.base/java.security.cert.CertPathBuilder.build(Unknown Source) ~[na:na]
	... 37 common frames omitted
```

対象のサーバーを信頼するために、CA証明書を`sslRootCert`で指定します。

```
docker run \
  --rm \
  -m 512m \
  -p 8080:8080 \
  -e SPRING_R2DBC_URL="r2dbc:postgresql://host.docker.internal:5432/demo?sslMode=VERIFY_CA&sslRootCert=/certs/root.crt" \
  -v ${PWD}/certs:/certs \
  ghcr.io/making/demo-r2dbc 
```

これで`VERIFY_CA`でも次のログのようにPostgreSQLに接続できます。

```
Setting Active Processor Count to 4
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 512M, Thread Count: 50, Loaded Class Count: 14180, Headroom: 0%)
Adding 129 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.5)

2021-04-18 15:14:07.243  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Starting DemoR2dbcApplication v0.0.1-SNAPSHOT using Java 11.0.10 on c87ecd21dfb7 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2021-04-18 15:14:07.246  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : No active profile set, falling back to default profiles: default
2021-04-18 15:14:08.101  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-04-18 15:14:08.112  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 0 R2DBC repository interfaces.
2021-04-18 15:14:10.245  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-04-18 15:14:10.541  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
2021-04-18 15:14:10.555  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Started DemoR2dbcApplication in 3.877 seconds (JVM running for 4.405)
```

### sslMode=VERIFY_CAの場合

次に`sslMode=VERIFY_FULL`を設定して通信を暗号化します。

```
docker run \
  --rm \
  -m 512m \
  -p 8080:8080 \
  -e SPRING_R2DBC_URL="r2dbc:postgresql://host.docker.internal:5432/demo?sslMode=VERIFY_FULL&sslRootCert=/certs/root.crt" \
  -v ${PWD}/certs:/certs \
  ghcr.io/making/demo-r2dbc 
```

`generate-certs.sh`で作成した証明書のCommon Nameは`*.sslip.io`であり、`SPRING_R2DBC_URL`のhostnameに指定した`host.docker.internal`に合致しない為、hostnameの検証に失敗し、次のログのように`The hostname 'host.docker.internal/192.168.65.2' could not be verified.`というエラーメッセージが出力されます。

```
Setting Active Processor Count to 4
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 512M, Thread Count: 50, Loaded Class Count: 14180, Headroom: 0%)
Adding 129 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.5)

2021-04-18 15:14:37.819  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Starting DemoR2dbcApplication v0.0.1-SNAPSHOT using Java 11.0.10 on 4588d584368b with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2021-04-18 15:14:37.826  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : No active profile set, falling back to default profiles: default
2021-04-18 15:14:38.644  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-04-18 15:14:38.656  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 0 R2DBC repository interfaces.
2021-04-18 15:14:40.315  WARN 1 --- [tor-tcp-epoll-1] i.r.p.client.DefaultHostnameVerifier     : Server name validation failed: hostname host.docker.internal does not match common name *.sslip.io
2021-04-18 15:14:40.358  WARN 1 --- [tor-tcp-epoll-1] i.r.p.client.DefaultHostnameVerifier     : Server name validation failed: hostname host.docker.internal does not match common name *.sslip.io
2021-04-18 15:14:40.367  WARN 1 --- [           main] onfigReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'initializer' defined in class path resource [lol/maki/demo/config/R2dbcConfig.class]: Invocation of init method failed; nested exception is org.springframework.r2dbc.connection.init.UncategorizedScriptException: Failed to execute database script; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection; nested exception is io.r2dbc.postgresql.client.AbstractPostgresSSLHandlerAdapter$PostgresqlSslException: The hostname 'host.docker.internal/192.168.65.2' could not be verified.
2021-04-18 15:14:40.389  INFO 1 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-04-18 15:14:40.414 ERROR 1 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'initializer' defined in class path resource [lol/maki/demo/config/R2dbcConfig.class]: Invocation of init method failed; nested exception is org.springframework.r2dbc.connection.init.UncategorizedScriptException: Failed to execute database script; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection; nested exception is io.r2dbc.postgresql.client.AbstractPostgresSSLHandlerAdapter$PostgresqlSslException: The hostname 'host.docker.internal/192.168.65.2' could not be verified.
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786) ~[spring-beans-5.3.6.jar:5.3.6]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) ~[spring-beans-5.3.6.jar:5.3.6]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.6.jar:5.3.6]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.6.jar:5.3.6]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.6.jar:5.3.6]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.6.jar:5.3.6]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.6.jar:5.3.6]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.6.jar:5.3.6]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.6.jar:5.3.6]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.6.jar:5.3.6]
	at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:63) ~[spring-boot-2.4.5.jar:2.4.5]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:782) ~[spring-boot-2.4.5.jar:2.4.5]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:774) ~[spring-boot-2.4.5.jar:2.4.5]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) ~[spring-boot-2.4.5.jar:2.4.5]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) ~[spring-boot-2.4.5.jar:2.4.5]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1340) ~[spring-boot-2.4.5.jar:2.4.5]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329) ~[spring-boot-2.4.5.jar:2.4.5]
	at lol.maki.demo.DemoR2dbcApplication.main(DemoR2dbcApplication.java:10) ~[classes/:0.0.1-SNAPSHOT]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na]
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[workspace/:na]
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[workspace/:na]
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[workspace/:na]
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[workspace/:na]
Caused by: org.springframework.r2dbc.connection.init.UncategorizedScriptException: Failed to execute database script; nested exception is org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection; nested exception is io.r2dbc.postgresql.client.AbstractPostgresSSLHandlerAdapter$PostgresqlSslException: The hostname 'host.docker.internal/192.168.65.2' could not be verified.
	at org.springframework.r2dbc.connection.init.DatabasePopulator.lambda$populate$4(DatabasePopulator.java:63) ~[spring-r2dbc-5.3.6.jar:5.3.6]
	at reactor.core.publisher.Mono.lambda$onErrorMap$30(Mono.java:3474) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Mono.lambda$onErrorResume$32(Mono.java:3564) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoUsingWhen$ResourceSubscriber.onError(MonoUsingWhen.java:208) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Operators.error(Operators.java:197) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoError.subscribe(MonoError.java:52) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4150) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxRetry$RetrySubscriber.onError(FluxRetry.java:94) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onError(FluxPeekFuseable.java:234) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:172) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:221) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onError(FluxPeek.java:221) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.pool.AbstractPool$Borrower.fail(AbstractPool.java:418) ~[reactor-pool-0.2.4.jar:0.2.4]
	at reactor.pool.SimpleDequePool.lambda$drainLoop$7(SimpleDequePool.java:390) ~[reactor-pool-0.2.4.jar:0.2.4]
	at reactor.core.publisher.FluxDoOnEach$DoOnEachSubscriber.onError(FluxDoOnEach.java:186) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onError(FluxMap.java:259) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Operators.error(Operators.java:197) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoError.subscribe(MonoError.java:52) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4150) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:172) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Operators.error(Operators.java:197) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoError.subscribe(MonoError.java:52) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4150) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Operators.error(Operators.java:197) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoError.subscribe(MonoError.java:52) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.Mono.subscribe(Mono.java:4150) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:132) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoDelayUntil$DelayUntilCoordinator.onError(MonoDelayUntil.java:200) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onError(FluxMapFuseable.java:140) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:192) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:259) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onError(MonoIgnoreThen.java:270) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoSubscribeOn$SubscribeOnSubscriber.onError(MonoSubscribeOn.java:152) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.MonoCompletionStage.lambda$subscribe$0(MonoCompletionStage.java:79) ~[reactor-core-3.4.5.jar:3.4.5]
	at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(Unknown Source) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(Unknown Source) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture.postComplete(Unknown Source) ~[na:na]
	at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(Unknown Source) ~[na:na]
	at io.r2dbc.postgresql.client.AbstractPostgresSSLHandlerAdapter.completeHandshakeExceptionally(AbstractPostgresSSLHandlerAdapter.java:73) ~[r2dbc-postgresql-0.8.7.RELEASE.jar:0.8.7.RELEASE]
	at io.r2dbc.postgresql.client.AbstractPostgresSSLHandlerAdapter.operationComplete(AbstractPostgresSSLHandlerAdapter.java:68) ~[r2dbc-postgresql-0.8.7.RELEASE.jar:0.8.7.RELEASE]
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:578) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:571) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:550) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:491) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:616) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.concurrent.DefaultPromise.setSuccess0(DefaultPromise.java:605) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:104) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.setHandshakeSuccess(SslHandler.java:1780) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.wrapNonAppData(SslHandler.java:964) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1421) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1253) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1300) ~[netty-handler-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508) ~[netty-codec-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447) ~[netty-codec-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) ~[netty-codec-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:795) ~[netty-transport-native-epoll-4.1.63.Final-linux-x86_64.jar:4.1.63.Final]
	at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:480) ~[netty-transport-native-epoll-4.1.63.Final-linux-x86_64.jar:4.1.63.Final]
	at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:378) ~[netty-transport-native-epoll-4.1.63.Final-linux-x86_64.jar:4.1.63.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.63.Final.jar:4.1.63.Final]
	at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
	Suppressed: java.lang.Exception: #block terminated with an error
		at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99) ~[reactor-core-3.4.5.jar:3.4.5]
		at reactor.core.publisher.Mono.block(Mono.java:1703) ~[reactor-core-3.4.5.jar:3.4.5]
		at org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer.execute(ConnectionFactoryInitializer.java:109) ~[spring-r2dbc-5.3.6.jar:5.3.6]
		at org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer.afterPropertiesSet(ConnectionFactoryInitializer.java:95) ~[spring-r2dbc-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.6.jar:5.3.6]
		at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.6.jar:5.3.6]
		at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.6.jar:5.3.6]
		at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:63) ~[spring-boot-2.4.5.jar:2.4.5]
		at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:782) ~[spring-boot-2.4.5.jar:2.4.5]
		at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:774) ~[spring-boot-2.4.5.jar:2.4.5]
		at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) ~[spring-boot-2.4.5.jar:2.4.5]
		at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) ~[spring-boot-2.4.5.jar:2.4.5]
		at org.springframework.boot.SpringApplication.run(SpringApplication.java:1340) ~[spring-boot-2.4.5.jar:2.4.5]
		at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329) ~[spring-boot-2.4.5.jar:2.4.5]
		at lol.maki.demo.DemoR2dbcApplication.main(DemoR2dbcApplication.java:10) ~[classes/:0.0.1-SNAPSHOT]
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
		at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:na]
		at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[na:na]
		at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[workspace/:na]
		at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[workspace/:na]
		at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[workspace/:na]
		at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[workspace/:na]
Caused by: org.springframework.dao.DataAccessResourceFailureException: Failed to obtain R2DBC Connection; nested exception is io.r2dbc.postgresql.client.AbstractPostgresSSLHandlerAdapter$PostgresqlSslException: The hostname 'host.docker.internal/192.168.65.2' could not be verified.
	at org.springframework.r2dbc.connection.ConnectionFactoryUtils.lambda$getConnection$0(ConnectionFactoryUtils.java:88) ~[spring-r2dbc-5.3.6.jar:5.3.6]
	at reactor.core.publisher.Mono.lambda$onErrorMap$31(Mono.java:3488) ~[reactor-core-3.4.5.jar:3.4.5]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.4.5.jar:3.4.5]
	... 69 common frames omitted
Caused by: io.r2dbc.postgresql.client.AbstractPostgresSSLHandlerAdapter$PostgresqlSslException: The hostname 'host.docker.internal/192.168.65.2' could not be verified.
	... 30 common frames omitted
```

エラーメッセージからわかるように、今回の環境ではPostgreSQLのIPアドレスは`192.168.65.2`です。[sslip.io](https://sslip.io/) の機能で、`192-168-65-2.sslip.io`を`192.168.65.2`に解決できるので、

```
$ nslookup 192-168-65-2.sslip.io
Server:		8.8.8.8
Address:	8.8.8.8#53

Non-authoritative answer:
Name:	192-168-65-2.sslip.io
Address: 192.168.65.2
```

証明書のCommon Nameに合致するようにPostgreSQLのhostnameを`192-168-65-2.sslip.io`に変更します。


```
docker run \
  --rm \
  -m 512m \
  -p 8080:8080 \
  -e SPRING_R2DBC_URL="r2dbc:postgresql://192-168-65-2.sslip.io:5432/demo?sslMode=VERIFY_FULL&sslRootCert=/certs/root.crt" \
  -v ${PWD}/certs:/certs \
  ghcr.io/making/demo-r2dbc 
```

これで`VERIFY_FULL`でも次のログのようにPostgreSQLに接続できます。

```
Setting Active Processor Count to 4
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 512M, Thread Count: 50, Loaded Class Count: 14180, Headroom: 0%)
Adding 129 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.5)

2021-04-18 15:16:46.891  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Starting DemoR2dbcApplication v0.0.1-SNAPSHOT using Java 11.0.10 on 303c1f93b565 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2021-04-18 15:16:46.896  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : No active profile set, falling back to default profiles: default
2021-04-18 15:16:47.767  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-04-18 15:16:47.780  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 7 ms. Found 0 R2DBC repository interfaces.
2021-04-18 15:16:49.932  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-04-18 15:16:50.185  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
2021-04-18 15:16:50.200  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Started DemoR2dbcApplication in 3.924 seconds (JVM running for 4.43)
```

これで安心。

### 別解: Paketo CA Certificates Buildpackを使用

`ghcr.io/making/demo-r2dbc`は[Paketo Buildpack](https://paketo.io)でビルドされています。
Paketo Buildpackを使っている場合は[CA Certificates Buildpack](https://paketo.io/docs/buildpacks/configuration/#ca-certificates) を使うことで、簡単にCA証明書をTrustStoreに追加することできます。

次のコマンドを実行して、[Binding](https://paketo.io/docs/buildpacks/configuration/#bindings) の仕様に合わせてディレクトリとファイルを作成します。

```
mkdir -p bindings/trusted-certs
echo ca-certificates > bindings/trusted-certs/type
cp certs/root.crt bindings/trusted-certs/
```

次の構造になります。

```
$ tree bindings 
bindings
`-- trusted-certs
    |-- root.crt
    `-- type

1 directory, 2 files
```

[Service Binding](https://github.com/k8s-service-bindings/spec) の仕様に合わせて次のコマンドを実行します。

```
docker run \
  --rm \
  -m 512m \
  -p 8080:8080 \
  -e SPRING_R2DBC_URL="r2dbc:postgresql://192-168-65-2.sslip.io:5432/demo?sslMode=VERIFY_FULL" \
  -e SERVICE_BINDING_ROOT=/bindings \
  -v ${PWD}/bindings:/bindings \
  ghcr.io/making/demo-r2dbc
```

次のログのようにPostgreSQLに接続できます。

```
Added 1 additional CA certificate(s) to system truststore
Setting Active Processor Count to 4
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 512M, Thread Count: 50, Loaded Class Count: 14180, Headroom: 0%)
Adding 130 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -agentpath:/layers/paketo-buildpacks_bellsoft-liberica/jvmkill/jvmkill-1.16.0-RELEASE.so=printHeapHistogram=1 -XX:ActiveProcessorCount=4 -XX:MaxDirectMemorySize=10M -Xmx123099K -XX:MaxMetaspaceSize=93988K -XX:ReservedCodeCacheSize=240M -Xss1M -Dorg.springframework.cloud.bindings.boot.enable=true

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.5)

2021-04-18 15:30:59.566  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Starting DemoR2dbcApplication v0.0.1-SNAPSHOT using Java 11.0.10 on aa73c23c4672 with PID 1 (/workspace/BOOT-INF/classes started by cnb in /workspace)
2021-04-18 15:30:59.571  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : No active profile set, falling back to default profiles: default
2021-04-18 15:31:00.419  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2021-04-18 15:31:00.431  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 0 R2DBC repository interfaces.
2021-04-18 15:31:02.595  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-04-18 15:31:02.852  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
2021-04-18 15:31:02.872  INFO 1 --- [           main] lol.maki.demo.DemoR2dbcApplication       : Started DemoR2dbcApplication in 3.92 seconds (JVM running for 4.467)
```

Bindingを行う前は`Adding 129 container CA certificates to JVM truststore`というメッセージが出力されていましたが、今回は
`Adding 130 container CA certificates to JVM truststore`というメッセージが出力されています。
用意した`root.crt`がTrustStoreに追加されるので、Driver側に`sslRootCert`を指定する必要がありません。

この手法はPostgreSQLに限らず任意のTLS通信に利用できるので、こちらの方が良いかもしれません。
