docker - 微服务内部通信时的 SSL 证书主机名问题

标签 docker ssl docker-compose microservices spring-cloud-zookeeper

我必须使用 SSL 保护微服务内部通信。我所有的微服务都是 spring boot 应用程序,我们在其中使用 zookeeper 作为发现服务器。内部服务通信通过 rest 模板和 feign client 进行。我们使用 Ribbon 作为客户端负载均衡器。 我们在所有微服务中设置了以下属性

spring.application.name=Application1
spring.cloud.zookeeper.discovery.enabled=true
spring.cloud.zookeeper.connectString=localhost:2181
spring.cloud.zookeeper.enabled=true
server.port=7800
spring.cloud.zookeeper.discovery.instance-ssl-port=7801

server.ssl.enabled=true
server.ssl.key-store-type=JKS
server.ssl.key-store=classpath:LP-PF1HMVQU.jks
server.ssl.key-store-password=123456
server.ssl.key-alias=LP-PF1HMVQU
server.ssl.protocol=TLS

我们必须使用自签名证书,我生成了相同的证书并将证书导入 JRE 信任库以使通信成为可能(SSL 握手)。这里的问题是我必须保持证书的 CN 与我系统的主机名 (LP-PF1HMVQU) 相同。这是因为当服务向 zookeeper 注册时,它存储机器名或主机名作为其地址,并在握手期间返回相同的地址。

服务注册到zookeeper

{"name":"employee-service","id":"b4c2204a-b00c-4102-b609-17d7f73f35d7","address":"LP-PF1HMVQU","port":7800,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"employee-service","metadata":{}},"registrationTimeUTC":1564658801106,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}

现在在生产环境中,我们将为每个服务提供一个 docker 容器,并且每个服务可以有多个 docker 容器。这些 docker 容器已注册到 zookeeper 并保留容器的 IP 地址。

我应该如何创建证书,CN 名称应该是什么,以便它匹配任何 IP 地址。我试过通配符 * 作为 CN 名称,但没有用。

请建议如何实现这一目标。

最佳答案

what should be the CN name, so that it matches any IP-Address

不要那样做,它不会起作用(如预期的那样)

HTTPS 和 IP 地址

虽然从技术上讲,您可以在 HTTPS URL 中拥有 IP 地址,例如 https://192.0.2.42/whatever,但它只会给您带来麻烦,因为它所附的证书需要提及那个IP,而不是一个名字,因为没有。这在技术上是可行的(参见 https://1.1.1.1/ 提供的证书)只是更困难/超出标准案例。

因此,我建议改为注册您想要的任何域名,然后将其用作满足您所有需求的后缀。如果该名称是可公开解析的,您甚至可以获得它们的 DV 证书。如果没有,您可能需要自己设置私有(private) CA。

你还说:

CN of the certificate same as my system's host name (LP-PF1HMVQU)

这很奇怪,因为它不是全名,而且肯定不可解析,所以没有 CA 会同意签署那种证书。如果这确实是您想要的(但请参阅下文),您无论如何都需要自己的私有(private) CA。

CN 和 SAN

第一个证书只有一个“主题”部分,您可以在其中放置一个 DN 对象,即某个实体的 X.400 描述,该实体可以是个人,也可以是抽象实体,例如组织,电子邮件地址或网站的主机名。

所以最初我们将网站主机名作为主题中的 CN 组件,并且浏览器与之匹配。

但很快就出现了为多个名称创建一个证书的需求,从“root”与“www”二元性开始,因此创建了一个扩展:Subject Alternative Names。

在那里,可以输入其他名称(或我们将在下面看到的 IP 地址)。如今,浏览器(以及更普遍的 HTTP 客户端)大多忽略主题中的内容,因此只关注“SAN”部分。

所以这是您需要放置 IP 地址的地方。

让我们再看看https://1.1.1.1/返回的证书。您可以在其中看到以下主题部分:

CN = cloudflare-dns.com
O = "Cloudflare, Inc."
L = San Francisco
ST = California
C = US

对于 SAN:

Not Critical
DNS Name: cloudflare-dns.com
DNS Name: *.cloudflare-dns.com
DNS Name: one.one.one.one
IP Address: 1.1.1.1
IP Address: 1.0.0.1
IP Address: 162.159.132.53
IP Address: 2606:4700:4700::1111
IP Address: 2606:4700:4700::1001
IP Address: 2606:4700:4700::64
IP Address: 2606:4700:4700::6400
IP Address: 162.159.36.1
IP Address: 162.159.46.1

因此,如果您真的想在证书中包含 IP 地址,则需要这样做。如果自己管理CA,那么技术上问题不大(需要确保使用

完整的详细信息(规范)位于 https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.6 您可以在这里和其他地方找到很多关于如何使用 IP 地址所需的 SAN 扩展来制作正确的 CSR/证书的说明。

请注意,您可以在 SAN 中为域名使用通配符,例如 *.example.com 但不能为 IP 地址使用通配符。所以你的“它匹配任何 IP 地址”似乎不是目标。看起来您可能正在寻找一个空白证书来绕过身份验证并使您的系统正常工作?如果是这样,请不要那样做并放弃这个想法:没有身份验证的 TLS 大多数情况下与纯文本一样糟糕,即使交换是加密的,因为您也不知道您在加密谁。

关于docker - 微服务内部通信时的 SSL 证书主机名问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57310401/

相关文章:

docker-compose 并在初始化时在 Postgres 中创建数据库

ios - 无法通过临时分发的 pushsharp 发送推送通知

python - SocketServer rfile.read() 非常非常慢

docker - 如何通过 dotnet sdk 将 .dcproj 添加到解决方案中

PHP 应用程序无法连接到 127.0.0.1 处的 docker mysql 容器

docker - kubernetes pods 无法与外界通信

wordpress - 如何在构建Docker镜像之前更改ElasticBeanstalk上的文件权限?

testing - docker-compose 与孤立的服务集一起运行?

docker - 如何检查应用程序是否已在容器内启动

node.js - 配置 AdonisJS 监听 HTTPS