TT Lab
开始
学习 学习路径 课程

隔离网络镜像与私有 CA

让每个工具都信任私有 CA

在 TT Lab 中继续学习

目标

创建私有根 CA 和服务器证书,用内部名称启动 HTTPS,并分别放入操作系统、Python 和 Node 的信任库。亲自测量哪个工具看哪个信任库,并整理成表,还要让服务器把中间 CA 证书链也一并发送。

为什么重要

内部镜像一旦使用 HTTPS,所有构建工具就都必须信任那个 CA。但信任库分为操作系统、certifi、Node 内置列表和 JVM 几种,只放进一个地方,就只有部分工具可用。在不能用的工具上把验证关掉,是最常见的事故。这个实验 Pod 连不上外部(只有 DNS),因为私有 CA 是隔离网络内部的事情。

步骤

  1. 用 /root/pki/ca.key 和 /root/pki/ca.crt 创建 CN 为 Airgap Internal Root CA 的根 CA(CA:TRUE,keyCertSign)。
  2. 用 /root/pki/server.key 和 /root/pki/server.crt,由该 CA 签发 repo.airgap.internal 服务器证书(SAN 中为 DNS 名称,用途为 serverAuth,不是 CA)。签名时给出的扩展保存为 /root/pki/server.ext。
  3. 在 /etc/hosts 中加入 127.0.0.1 repo.airgap.internal,并用 /root/pki/serve.py 启动一个服务器,通过 https://repo.airgap.internal:8443/ 提供 /root/pki/www/hello.txt(内容为 hello-airgap)。
  4. 把根 CA 以 airgap-root.crt 的名称放入操作系统信任库并更新。curl 必须在不带 --cacert 的情况下通过。
  5. 在 /etc/profile.d/airgap-ca.sh 中写入让 Python requests 和 httpx 使用操作系统证书包的环境变量。
  6. 在同一个文件中加入让 Node 信任私有根证书的环境变量。
  7. 不用环境变量(仅靠操作系统信任库),测量每个工具是否通过,把 curl、urllib、requests、httpx、node、go 六行,以 도구=os 或 도구=env(占位符为工具名称)的形式写入 /root/pki/trust-matrix.txt。
  8. 用根证书签发中间 CA(/root/pki/int.crt,pathlen 0),再用该中间 CA 签发 mirror.airgap.internal 证书(/root/pki/mirror.crt)。在 /etc/hosts 中加入该名称,并用把叶证书和中间证书连在一起的 /root/pki/mirror-chain.crt,在 9443 端口启动同样的服务器。

参考

创建私有根 CA

用 /root/pki/ca.key 和 /root/pki/ca.crt 创建 CN 为 Airgap Internal Root CA 的根 CA(CA:TRUE,keyCertSign)。

给 openssl req 加上 -x509,就会直接生成自签名证书,而不是请求。扩展可以通过 -addext 给出,根 CA 需要的是基本约束(CA)和密钥用途(证书签名)。

签发带有 SAN 的服务器证书

用 /root/pki/server.key 和 /root/pki/server.crt,由根 CA 签发 repo.airgap.internal 服务器证书(SAN 为 DNS,serverAuth,不是 CA)。签名时给出的扩展保存为 /root/pki/server.ext。

生成密钥和签名请求(CSR)之后,用 CA 密钥签名时,通过扩展文件给出 subjectAltName 和 extendedKeyUsage。请注意,openssl x509 -req 默认不会把请求中的扩展带过去。

用内部名称启动 HTTPS

在 /etc/hosts 中加入 127.0.0.1 repo.airgap.internal,并用 /root/pki/serve.py 启动一个服务器,通过 https://repo.airgap.internal:8443/ 提供 /root/pki/www/hello.txt(hello-airgap)。

用 ssl 上下文包装 Python 标准库的 http.server,就成了 HTTPS 服务器。把证书文件和密钥文件交给 load_cert_chain。请放到后台启动,并用通过 --cacert 指定了根证书的 curl 来确认。

放入操作系统信任库

把根 CA 以 airgap-root.crt 放入操作系统信任库并更新。curl 必须在不带 --cacert 的情况下通过。

Debian 系列把文件以 .crt 扩展名放在指定目录中,再运行更新命令,就会重新生成连接成一个文件的证书包。更新命令的输出中会显示新增了几个。

让 Python requests 和 httpx 信任它

在 /etc/profile.d/airgap-ca.sh 中写入让 requests 和 httpx 使用操作系统证书包的环境变量。

requests 和 httpx 使用的不是操作系统信任库,而是 certifi 证书包。这两个库遵循的环境变量各不相同——请看阅读材料中的表。值是操作系统生成的证书包文件。

让 Node 信任它

在 /etc/profile.d/airgap-ca.sh 中加入让 Node 信任私有根证书的环境变量。

Node 使用构建时内置的列表,并且有一个环境变量可以向该列表中添加证书。它只在进程启动时读取一次,所以请在新的 shell 中确认。

测量各工具的信任情况表

不用环境变量,测量每个工具是否通过,把 curl、urllib、requests、httpx、node、go 以 도구=os 或 도구=env(占位符为工具名称)的形式写入 /root/pki/trust-matrix.txt。

用 env -i 清空环境,profile.d 中的变量也就没有了。在这种状态下通过,就说明仅靠操作系统信任库即可(os);失败,就说明需要环境变量(env)。Go 请写一个小程序,用 go run 运行。

中间 CA 与发送证书链

创建中间 CA /root/pki/int.crt(pathlen 0)和由该 CA 签发的 mirror.airgap.internal 证书 /root/pki/mirror.crt,并用把叶证书和中间证书连在一起的 /root/pki/mirror-chain.crt,在 9443 端口启动服务器。

中间 CA 也是 CA,所以需要基本约束,并用 pathlen 禁止在它之下再设置 CA。服务器的证书文件中,要在叶证书之后接上中间 CA 证书。客户端只知道根。