语境
由于某些原因,我需要生成:
- 根 CA
- 中间 CA(由根 CA 签名)
- 证书(由中间 CA 签名)
- 连锁,链条
我处于 Dockerized 环境中,有 3 个容器:
- 容器 A:Nginx 反向代理,解码 SSL(使用链 + 密钥)并将请求转发到容器 B
- 容器 B:Nginx(这里没什么特别的,响应的应用程序)
- 容器 C:需要 curl A 的应用程序(不使用不安全的标志)。我需要在这个容器上安装中间 CA
这看起来像是一个简单的问题,但当容器 C 基于 Debian 时,我就卡住了。例如,它在 Ubuntu 容器上工作得很好。它还可以与 Ubuntu 桌面虚拟机一起使用。我的中间 CA 也可以在我的 Mac 上使用 OSX 钥匙串存储。
这看起来像是 Debian 特有的问题。
我如何测试
我遵循了几个步骤: - 生成 ca/certs/chain - 在我的 Mac 上安装中间 CA - curl -XGEThttps://service.local在终端内:确定
然后,使用 Docker 在 ubuntu 上挂载中间 CA,然后调用 update-ca-certificates,并使用 curl 进行测试:OK
然后,使用 Docker 在 Debian 上挂载中间 CA,然后调用 update-ca-certificates,并使用 curl 进行测试:KO
脚本部分
我已经编写了整个 certs/ca/chain 生成的脚本,这里没有问题,除非您需要它们,否则我不会详细说明。
用于容器 C 的 Docker-compose
我正在尝试使用不同的操作系统,这就是为什么有几种服务,并且它显示我在 ubuntu 和几个版本的 Debian 之间做了完全相同的事情。
我通过不调用 update-ca-certificates 来采取一些捷径;相反,我直接在 /etc/ssl/certs 中挂载文件,因为它实际上并没有做太多事情...对于那些想知道的人:我也尝试在其他地方挂载文件,然后调用 update-ca-certificates,然后 curl,使用另一个版本的入口点,但最后的结果相同,它在 Ubuntu 上运行,而不是在 Debian 上运行。
version: '2'
services:
ubuntu:
image : "ubuntu:16.04"
volumes :
- './local_ca/LOCAL_CA.crt:/etc/ssl/certs/local_ca.pem:ro'
- './entrypoint.sh:/entrypoint.sh'
command : 'bash -c "/entrypoint.sh"'
debian7:
image : "debian:wheezy"
volumes :
- './local_ca/LOCAL_CA.crt:/etc/ssl/certs/local_ca.pem:ro'
- './entrypoint.sh:/entrypoint.sh'
command : 'bash -c "/entrypoint.sh"'
debian8:
image : "debian:jessie"
volumes :
- './local_ca/LOCAL_CA.crt:/etc/ssl/certs/local_ca.pem:ro'
- './entrypoint.sh:/entrypoint.sh'
command : 'bash -c "/entrypoint.sh"'
debian9:
image : "debian:stretch"
volumes :
- './local_ca/LOCAL_CA.crt:/etc/ssl/certs/local_ca.pem:ro'
- './entrypoint.sh:/entrypoint.sh'
command : 'bash -c "/entrypoint.sh"'
入口点
为了举例,假设 IP 已知,并在以下模板中替换:
#!/bin/bash
apt-get update
apt-get install -y curl
echo '{{ip_of_reverse_proxy}} service.local' >> /etc/hosts
curl -XGET https://service.local
正如我之前所说,我也做了一个版本,其中我调用 update-ca-certificates 而不是直接挂载,但这没有任何区别,它在 Ubuntu 上运行,但在 Debian 上却不行
docker-compose 日志
以下是输出日志,我们将其截断,以便我们只获得有趣的部分。如您所见,ubuntu 上的 curl 使用 JSON 进行回答,而 debian 拒绝证书验证,因为 root ca 不受信任。
ubuntu_1 | {"_links":{"self":{"href":"\/"}}}
debian7_1 | curl performs SSL certificate verification by default, using a "bundle"
[...] (see debian9_1 logs)
debian8_1 | curl performs SSL certificate verification by default, using a "bundle"
[...] (see debian9_1 logs)
debian9_1 | curl: (60) SSL certificate problem: self signed certificate in certificate chain
debian9_1 | More details here: https://curl.haxx.se/docs/sslcerts.html
debian9_1 |
debian9_1 | curl performs SSL certificate verification by default, using a "bundle"
debian9_1 | of Certificate Authority (CA) public keys (CA certs). If the default
debian9_1 | bundle file isn't adequate, you can specify an alternate file
debian9_1 | using the --cacert option.
debian9_1 | If this HTTPS server uses a certificate signed by a CA represented in
debian9_1 | the bundle, the certificate verification probably failed due to a
debian9_1 | problem with the certificate (it might be expired, or the name might
debian9_1 | not match the domain name in the URL).
debian9_1 | If you'd like to turn off curl's verification of the certificate, use
debian9_1 | the -k (or --insecure) option.
问题
问题 1:我注入了完全相同的文件并遵循完全相同的过程,为什么它在 ubuntu 上有效,但在 debian 上却不行?它们不是共享同一个基础吗?
问题 2:什么是适合 Debian 的解决方案?我真的需要注入并安装根 CA 吗?(这样做是有效的,但对我来说这看起来很奇怪,因为中间 CA 就足够了)
答案1
经过进一步调查,ubuntu 和 debian 之间最大的区别在于所使用的 SSL 库:
- 在 Debian 上,curl 已使用 OpenSSL 进行预编译
- 在 Ubuntu 上,curl 已使用 GnuTLS 进行预编译
我在 Debian 上使用 GnuTLS 重新编译了 curl,并且仅使用中间 CA 就可以正常工作。
我在 Ubuntu 上使用 OpenSSL 重新编译了 curl,现在如果我希望我的请求通过,就必须信任根 CA。
答案2
您不需要在依赖方(容器 C)中安装任何从属 CA 证书。
RFC 5246 7.4.2规定服务器必须以链的形式提供所有下属 CA 证书。也就是说,容器 A 中的 Ngnix 服务器必须配置为在连接时将证书(根 CA 证书除外)发送给客户端。
只需要在客户端(容器 C)上安装根 CA 证书,它就可以信任服务器提供的链。
答案3
将根 CA 放入/etc/ssl/certs/yourCAnamehere.pem
文件中,然后update-ca-certificates --fresh
在容器 C 上运行
由于根 CA 不受信任,因此该链(中间 CA 也是如此)不受信任。通过将其添加到受信任的 CA,您应该能够正常执行请求