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

隔离网络镜像与私有 CA

HTTPS 内部 Maven 镜像,并让 JVM 信任

在 TT Lab 中继续学习

目标

在联网的一侧收集依赖和插件,用 HTTPS 搭建内部 Maven 仓库,并通过 settings.xml 的 mirror 转发所有请求。让 JVM 信任私有 CA,用隔离网络一侧的新本地仓库构建,并完成对导入清单中遗漏的插件进行追加导入的流程。

为什么重要

Java 构建在隔离网络中的失败有三层——仓库地址、证书,以及导入清单中的漏洞。地址由一行 mirror 解决,证书由 JVM 信任库解决,漏洞则靠“按实际要执行的 goal 制作清单”的习惯来堵住。这个 Pod 能访问互联网(80/443),所以承担下载端的角色,而在隔离网络一侧,mirrorOf * 会把所有请求转到内部仓库,使外部无法使用。评分器根据本地仓库的 _remote.repositories 和内部服务器的访问记录,确认内容是从哪里下载的。

步骤

  1. 在 /root/mvn/app 中创建 pom.xml(gson 2.11.0,固定插件版本)和 src/main/java/demo/App.java,并用新的本地仓库 /root/mvn/outside-repo 运行 package。
  2. 把 /root/mvn/outside-repo 搬到 /srv/maven,但要去掉 _remote.repositories、*.lastUpdated 和 resolver-status.properties。
  3. 在 /root/pki 中创建 CN 为 Airgap Internal Root CA 的根证书(ca.crt、ca.key)和 maven.airgap.internal 服务器证书(maven.crt、maven.key,带 SAN),并把该名称加入 /etc/hosts。
  4. 用 /root/mvn/nginx.conf 启动 nginx,让 https://maven.airgap.internal:8443/ 提供 /srv/maven。访问记录写入 /root/mvn/access.log。
  5. 在 ~/.m2/settings.xml 中写入 id 为 airgap-internal、mirrorOf 为 * 的 mirror。同时创建扮演联网一侧时使用的空配置 /root/mvn/outside-settings.xml。
  6. 用隔离网络一侧的新本地仓库 /root/mvn/inside-repo 运行 package,把失败的输出保存到 /root/mvn/pkix.log。
  7. 让 JVM 信任私有根证书(不使用关闭验证的选项)。
  8. 用同样的命令让隔离网络一侧的构建通过。
  9. 把导致 mvn clean package 失败的制品坐标,以 groupId:artifactId:version 的形式写入 /root/mvn/missing.txt,在联网的一侧下载后加入内部仓库,再让隔离网络一侧的 clean package 通过。

参考

下载端:用新的本地仓库构建并收集

在 /root/mvn/app 中创建 pom.xml 和 App.java,并用新的本地仓库 /root/mvn/outside-repo 运行 package。

可以通过系统属性更改本地仓库的位置。给出新的目录,就只会堆放这次构建实际下载的内容。如果不在 POM 中固定插件版本,这个 Maven 默认的 compiler 就不认识 JDK 21 的设置。

去掉追踪文件,变成内部仓库

把 /root/mvn/outside-repo 搬到 /srv/maven,但要去掉追踪文件(_remote.repositories、*.lastUpdated、resolver-status.properties)。

内部仓库保持文件布局原样即可。追踪文件是下载一侧的本地仓库记录“从哪里下载”的记录,不应留在仓库中。可以用 find 按名称挑出来删除。

用私有 CA 签发镜像证书

在 /root/pki 中创建根证书(ca.crt、ca.key,CN 为 Airgap Internal Root CA)和 maven.airgap.internal 证书(maven.crt、maven.key,带 SAN),并把该名称加入 /etc/hosts。

根证书是 CA:TRUE 的自签名,服务器证书则用根证书签名,同时通过扩展文件给出 SAN。这与在私有 CA 模块中做过的流程相同。

用 nginx 启动 HTTPS 内部仓库

用 /root/mvn/nginx.conf 启动 nginx,让 https://maven.airgap.internal:8443/ 提供 /srv/maven,并把访问记录写入 /root/mvn/access.log。

Maven 仓库是静态文件,所以一个 root 就够了。在这个 Pod 中无法开放 1024 以下的端口,pid 和日志路径必须移到可写的位置。请先用 -t 检查。

用 mirrorOf * 转发所有请求

在 ~/.m2/settings.xml 中写入 id 为 airgap-internal、mirrorOf 为 *、url 为 https://maven.airgap.internal:8443/ 的 mirror,并创建空配置 /root/mvn/outside-settings.xml。

用户配置文件位于主目录的 .m2 之下。给 mirrorOf 写上星号,就会把 POM 中声明的仓库也全部截获。用于外部角色的配置,只需是没有 mirror 的最小 settings 元素。

JVM 不认识的 CA——记录 PKIX 错误

用新的本地仓库 /root/mvn/inside-repo 运行 package,把失败的输出保存到 /root/mvn/pkix.log。

让 curl 知道根证书,与让 JVM 信任根证书,是两回事。请保存失败的完整输出,并在报错行中找出关于证书路径的说明。

把根证书放进 JVM 信任库

让 JVM 信任私有根证书(不使用关闭验证的选项)。

JDK 中有处理信任库的工具,也有直接指向默认信任库(cacerts)的选项。文档写明了初始密码。如果是 Ubuntu,还有一条路:更新操作系统信任库时连带更新 JVM 信任库。

隔离网络一侧的构建通过

用与第 6 步相同的命令(/root/mvn/inside-repo,package)让构建通过。

JVM 信任根证书之后,同一条命令应该能通过。通过之后,请看隔离网络一侧本地仓库的追踪文件中写的是哪个仓库 id。

clean 这一个词引出的追加导入

把 mvn clean package 失败的原因坐标,以 groupId:artifactId:version 的形式写入 /root/mvn/missing.txt,在联网的一侧下载后加入内部仓库,再让隔离网络一侧的 clean package 通过。

报错行会告诉你找不到哪个插件。扮演外部角色时,用空配置文件和外部专用的本地仓库运行同样的 goal,就能收集到那个插件。搬过去之后如果仍然失败,请把报错的句子读完——之前的失败已被记录下来。