首页 > 解决方案 > 微服务内部通信时的 SSL 证书主机名问题

问题描述

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

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 名称,但它不起作用。

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

标签: dockerssldocker-composemicroservicesspring-cloud-zookeeper

解决方案


CN 名称应该是什么,以便它匹配任何 IP 地址

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

HTTPS 和 IP 地址

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

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

你还说:

证书的 CN 与我系统的主机名相同 (LP-PF1HMVQU)

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

CN 和 SAN

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

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

但是很快就需要为多个名称提供一个证书,从“root”与“www”二元性开始,因此创建了一个扩展:主题备用名称。

在那里,可以输入其他名称(或我们将在下面看到的 IP 地址)。如今,浏览器(以及更普遍的 HTTP 客户端)大多忽略主题中的内容,因此CN, 只关注“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 扩展。

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


推荐阅读