【发布时间】:2020-11-30 22:14:04
【问题描述】:
动机
我在尝试使用 Let's Encrypt 通过 SSL 使用 Traefik 代理 PostgreSQL 时遇到问题。 我做了一些研究,但没有很好的记录,我想确认我的观察结果,并为所有面临这种情况的人留下记录。
配置
我使用最新版本的 PostgreSQL v12 和 Traefik v2。我想使用 Let's Encrypt 通过 TLS 从 tcp://example.com:5432 -> tcp://postgresql:5432 构建一个纯 TCP 流。
Traefik 服务配置如下:
version: "3.6"
services:
traefik:
image: traefik:latest
restart: unless-stopped
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./configuration/traefik.toml:/etc/traefik/traefik.toml:ro"
- "./configuration/dynamic_conf.toml:/etc/traefik/dynamic_conf.toml"
- "./letsencrypt/acme.json:/acme.json"
networks:
- backend
ports:
- "80:80"
- "443:443"
- "5432:5432"
networks:
backend:
external: true
使用静态设置:
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.web.http]
[entryPoints.web.http.redirections.entryPoint]
to = "websecure"
scheme = "https"
[entryPoints.websecure]
address = ":443"
[entryPoints.websecure.http]
[entryPoints.websecure.http.tls]
certresolver = "lets"
[entryPoints.postgres]
address = ":5432"
PostgreSQL服务配置如下:
version: "3.6"
services:
postgresql:
image: postgres:latest
environment:
- POSTGRES_PASSWORD=secret
volumes:
- ./configuration/trial_config.conf:/etc/postgresql/postgresql.conf:ro
- ./configuration/trial_hba.conf:/etc/postgresql/pg_hba.conf:ro
- ./configuration/initdb:/docker-entrypoint-initdb.d
- postgresql-data:/var/lib/postgresql/data
networks:
- backend
#ports:
# - 5432:5432
labels:
- "traefik.enable=true"
- "traefik.docker.network=backend"
- "traefik.tcp.routers.postgres.entrypoints=postgres"
- "traefik.tcp.routers.postgres.rule=HostSNI(`example.com`)"
- "traefic.tcp.routers.postgres.tls=true"
- "traefik.tcp.routers.postgres.tls.certresolver=lets"
- "traefik.tcp.services.postgres.loadBalancer.server.port=5432"
networks:
backend:
external: true
volumes:
postgresql-data:
看来我的 Traefik 配置是正确的。日志中的一切正常,仪表板中的所有部分都标记为成功(没有警告,没有错误)。所以我对上面的 Traefik 配置很有信心。完整的流程大约是:
EntryPoint(':5432') -> HostSNI(`example.com`) -> TcpRouter(`postgres`) -> Service(`postgres@docker`)
但是,它可能在 PostgreSQL 方面有限制。
调试
问题是我无法连接 PostgreSQL 数据库。我总是收到超时错误。
我已检查 PostgreSQL 是否正常监听(超时错误的主要原因):
# - Connection Settings -
listen_addresses = '*'
port = 5432
我检查了我可以在主机上(容器外)连接 PostgreSQL:
psql --host 172.19.0.4 -U postgres
Password for user postgres:
psql (12.2 (Ubuntu 12.2-4), server 12.3 (Debian 12.3-1.pgdg100+1))
Type "help" for help.
postgres=#
因此,我知道 PostgreSQL 在其容器之外进行侦听,因此 Traefik 应该能够绑定流。 我还检查了外部 traefik 是否可以访问服务器:
sudo tcpdump -i ens3 port 5432
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens3, link-type EN10MB (Ethernet), capture size 262144 bytes
09:02:37.878614 IP x.y-z-w.isp.com.61229 > example.com.postgresql: Flags [S], seq 1027429527, win 64240, options [mss 1452,nop,wscale 8,nop,nop,sackOK], length 0
09:02:37.879858 IP example.com.postgresql > x.y-z-w.isp.com.61229: Flags [S.], seq 3545496818, ack 1027429528, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
09:02:37.922591 IP x.y-z-w.isp.com.61229 > example.com.postgresql: Flags [.], ack 1, win 516, length 0
09:02:37.922718 IP x.y-z-w.isp.com.61229 > example.com.postgresql: Flags [P.], seq 1:9, ack 1, win 516, length 8
09:02:37.922750 IP example.com.postgresql > x.y-z-w.isp.com.61229: Flags [.], ack 9, win 502, length 0
09:02:47.908808 IP x.y-z-w.isp.com.61229 > example.com.postgresql: Flags [F.], seq 9, ack 1, win 516, length 0
09:02:47.909578 IP example.com.postgresql > x.y-z-w.isp.com.61229: Flags [P.], seq 1:104, ack 10, win 502, length 103
09:02:47.909754 IP example.com.postgresql > x.y-z-w.isp.com.61229: Flags [F.], seq 104, ack 10, win 502, length 0
09:02:47.961826 IP x.y-z-w.isp.com.61229 > example.com.postgresql: Flags [R.], seq 10, ack 104, win 0, length 0
所以,我想知道为什么连接不能成功。 Traefik 和 PostgreSQL 之间一定有问题。
SNI 不兼容?
即使我删除了 TLS 配置,问题仍然存在,所以我不认为 TLS 是这个问题的根源。
然后我搜索了一下,发现很少有类似问题的帖子:
据我了解,PostgreSQL 的 SSL 协议是自定义协议,暂时不支持SNI,可能永远不会支持。如果正确,它将确认 Traefik 目前无法代理 PostgreSQL,这是一个限制。
通过写这篇文章,我想确认我的观察结果,同时在 Stack Overflow 上留下一个可见的记录,给任何面临同样问题并寻求帮助的人。那么我的问题是:是否可以使用 Traefik 代理 PostgreSQL?
更新
有趣的观察,如果使用 HostSNI('*') 和 Let's Encrypt:
labels:
- "traefik.enable=true"
- "traefik.docker.network=backend"
- "traefik.tcp.routers.postgres.entrypoints=postgres"
- "traefik.tcp.routers.postgres.rule=HostSNI(`*`)"
- "traefik.tcp.routers.postgres.tls=true"
- "traefik.tcp.routers.postgres.tls.certresolver=lets"
- "traefik.tcp.services.postgres.loadBalancer.server.port=5432"
仪表板中的所有内容都标记为成功,但 Let's Encrypt 不能执行通配符 * 的 DNS 挑战,它会在日志中抱怨:
time="2020-08-12T10:25:22Z" level=error msg="Unable to obtain ACME certificate for domains \"*\": unable to generate a wildcard certificate in ACME provider for domain \"*\" : ACME needs a DNSChallenge" providerName=lets.acme routerName=postgres@docker rule="HostSNI(`*`)"
当我尝试以下配置时:
labels:
- "traefik.enable=true"
- "traefik.docker.network=backend"
- "traefik.tcp.routers.postgres.entrypoints=postgres"
- "traefik.tcp.routers.postgres.rule=HostSNI(`*`)"
- "traefik.tcp.routers.postgres.tls=true"
- "traefik.tcp.routers.postgres.tls.domains[0].main=example.com"
- "traefik.tcp.routers.postgres.tls.certresolver=lets"
- "traefik.tcp.services.postgres.loadBalancer.server.port=5432"
错误从日志中消失了,在两种设置中,仪表板似乎都正常,但流量没有路由到 PostgreSQL(超时)。无论如何,从配置中删除 SSL 会使流程完整(并且不安全):
labels:
- "traefik.enable=true"
- "traefik.docker.network=backend"
- "traefik.tcp.routers.postgres.entrypoints=postgres"
- "traefik.tcp.routers.postgres.rule=HostSNI(`*`)"
- "traefik.tcp.services.postgres.loadBalancer.server.port=5432"
那么就可以连接PostgreSQL数据库了:
time="2020-08-12T10:30:52Z" level=debug msg="Handling connection from x.y.z.w:58389"
【问题讨论】:
-
PostgreSQL 根本不使用 http,因为...它不是 Web 服务器。那么 - 这个“traefik”东西可以像 haproxy 一样路由普通的 tcp 吗?
-
@RichardHuxton,据我了解:是的,如果两个规则都存在,“traefik”确实完全支持 HTTP 之前的 TCP(请参阅docs.traefik.io/routing/routers/#configuring-tcp-routers)。在我的配置中,您可以检查这是纯 TCP 而不是 HTTP。
-
恐怕我根本不知道 traefik,但是 postgres 路由器上的 TLS 东西对我来说没有意义。如果你只是转发 tcp,你为什么要摆弄它?
-
@RichardHuxton,好吧,我不想在网络上清楚地公开 postgresql 端口(在通过此流程发送所有凭据之后),我想从 postgresql 然后从 Traefik 撤回 TLS 配置Let's Encrypt 可以自动接管它。另一方面,即使我删除了 TLS 配置,流量也不会以任何一种方式路由,这似乎与 SNI 问题有关。
-
@khashashin,还没有。我认为从现在开始唯一的解决方法是像往常一样加密 PSQL 连接并设置 Traefik 让 SSL 通过。但是你失去了 LE 的好处。
标签: postgresql tcp proxy traefik sni