VCF私有云中自签名证书配置全攻略:从原理到PAIS部署实践
1. 项目概述与核心痛点最近在帮一个医疗信息化团队部署一套基于VMware Cloud FoundationVCF的私有AI服务Private AI Services 简称PAIS环境。这个环境主要用于处理一些敏感的医疗数据分析和模型训练比如辅助诊断影像分析、病历文本挖掘等。由于数据隐私和安全合规的硬性要求整个服务必须运行在内网并且所有组件间的通信都需要启用TLS加密。在预算和流程上暂时没法走正规的CA证书颁发机构渠道去申请受信证书所以自签名证书就成了唯一的选择。听起来很简单不就是生成个证书然后配上去吗但实际操作下来从VCF的管理平面到PAIS的各个微服务组件再到客户端连接这一路踩的坑简直能写满一张A4纸。最典型的问题就是你在浏览器或者用curl访问服务时那个经典的“您的连接不是私密连接”或者“SSL certificate problem: self signed certificate”错误。在PAIS这种复杂的、容器化、微服务架构的环境里这个问题会被放大因为证书需要在多个层级被信任VCF Manager、负载均衡器、Kubernetes Ingress Controller、以及跑在Pod里的各个服务本身。所以这篇指南的目的就是把我从生成证书开始到最终让PAIS所有服务都能被内网客户端无警告访问的完整过程、核心原理和那些“坑点”记录下来。无论你是运维工程师、架构师还是开发者只要你在处理VCF、PAIS或者任何类似私有云环境下自签名证书的配置希望这篇“避坑实录”能帮你省下大量排查时间。2. 自签名证书的核心原理与VCF/PAIS环境特殊性在开始动手之前我们必须搞清楚自签名证书和受信CA签发的证书本质区别是什么以及这对VCF和PAIS意味着什么。2.1 自签名证书的信任链问题一个标准的TLS/SSL证书信任链是这样的你的服务证书Server Certificate由一个中间CA证书Intermediate CA Certificate签名而这个中间CA证书又由一个根CA证书Root CA Certificate签名。你的操作系统或浏览器里预置了这些受信的根CA证书列表。当客户端连接到你的服务时它会收到服务证书并沿着这个链向上验证直到找到一个它信任的根CA验证就通过了。自签名证书则完全不同。它自己就是自己的根CA。也就是说证书的“颁发者”Issuer和“主题”Subject通常是同一个。没有任何公共的、预置的根CA为它背书。因此所有客户端浏览器、curl、openssl、Java应用等在默认情况下都会拒绝信任它抛出安全警告。注意自签名证书在加密能力上和CA签发的证书没有区别它同样能提供强加密的HTTPS连接。问题的核心 solely 在于“信任”。你必须手动地将这个自签名证书的根CA也就是证书本身或者你专门创建的CA证书安装到每一个需要连接该服务的客户端信任库中。2.2 VCF与PAIS架构下的证书层级在VCF环境中部署PAIS证书的配置涉及多个层面理解这个层级对排查问题至关重要VCF管理平面这是入口。VCF Manager本身有一个管理界面可能还有NSX Manager、vCenter等。这些服务可能已经使用了VCF内置或你之前配置的证书。负载均衡器如NSX ALB/AviPAIS的入口流量通常由负载均衡器接收。你需要在这里配置一个包含私钥和证书的SSL证书对象并将其绑定到虚拟服务Virtual Service。这个证书就是客户端浏览器第一个会遇到的。Kubernetes IngressPAIS部署在由VCF管理的Kubernetes集群通常是Tanzu Kubernetes Grid上。外部流量通过负载均衡器后会到达Kubernetes的Ingress资源。Ingress Controller如Contour、NGINX也需要使用证书来终止TLS或者进行TLS透传。PAIS服务内部PAIS本身由多个微服务组成如模型服务、数据服务、API网关等。这些服务之间通过Service Mesh如Istio或直接通过Kubernetes Service进行通信。如果启用了mTLS双向TLS那么每个服务都需要自己的证书和信任库。我们的核心工作就是确保第2层负载均衡器使用的自签名证书其根CA被所有内网客户端信任。同时也要确保内部服务间的证书信任如果涉及正确配置。3. 证书生成一步错步步错很多坑其实在生成证书的那一刻就埋下了。这里我推荐使用一个自建的私有CA来为所有服务签发证书而不是为每个服务生成单独的自签名证书。这样做有两个巨大优势一是你只需要将这一个私有CA的根证书导入客户端它签发的所有证书都会被信任二是管理起来更规范。3.1 创建私有根CA首先我们创建自己的根CA。# 1. 创建用于存放CA的目录 mkdir -p my_private_ca cd my_private_ca # 2. 生成根CA的私钥使用强密码保护 openssl genrsa -aes256 -out ca.key 4096 # 系统会提示你输入并验证密码。请务必牢记此密码。 # 3. 生成根CA的自签名证书有效期为10年 openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj /CCN/STBeijing/LBeijing/OMyCompany/OUIT/CNMyPrivateRootCA关键参数解析-subj: 这里设置了证书的主题信息。CNCommon Name通常被用作CA的名称。在内部环境你可以根据自己组织情况设置C国家、ST省、O组织等字段。特别注意对于现代浏览器和工具CN的作用在减弱更多依赖Subject Alternative NameSAN但根CA的CN仍然重要。-days 3650: 根CA证书有效期很长设为10年减少维护频率。-aes256: 加密私钥增加安全性。现在你得到了两个核心文件ca.key加密的根CA私钥和ca.crt根CA证书。ca.crt就是将来要导入到所有客户端机器上的那个“信任根源”。3.2 为PAIS服务签发证书假设我们的PAIS服务将通过域名pais.internal.mycompany.com来访问。现在用刚才创建的CA为它签发证书。# 1. 创建服务私钥不加密便于服务器自动加载 openssl genrsa -out pais.internal.mycompany.com.key 2048 # 2. 创建证书签名请求CSR openssl req -new -key pais.internal.mycompany.com.key -out pais.internal.mycompany.com.csr -subj /CCN/STBeijing/LBeijing/OMyCompany/OUPAIS/CNpais.internal.mycompany.com关键一步创建包含SAN的扩展配置文件。这是现代TLS的强制要求尤其是Chrome等浏览器如果证书不包含SAN扩展即使CN正确也会报错。创建一个文件pais.ext内容如下authorityKeyIdentifierkeyid,issuer basicConstraintsCA:FALSE keyUsage digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName alt_names [alt_names] DNS.1 pais.internal.mycompany.com DNS.2 *.pais.internal.mycompany.com # 如果你需要通配符 # 如果有IP访问需求务必加上IP地址 # IP.1 10.1.1.100踩坑实录1最初我只配置了CN没有配SAN。结果Chrome和curl都报错“证书缺少主题备用名称(SAN)”。所以SAN扩展现在是必须的DNS.1的值应该和你要访问的域名完全一致。# 3. 使用根CA签署CSR生成最终的服务端证书 openssl x509 -req -in pais.internal.mycompany.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out pais.internal.mycompany.com.crt -days 365 -sha256 -extfile pais.ext参数解析-CAcreateserial: 首次签署时创建序列号文件。-days 365: 服务证书有效期通常为1年需要建立续订流程。-extfile pais.ext: 应用我们刚才创建的扩展配置文件注入SAN信息。现在你得到了服务端所需的三个文件pais.internal.mycompany.com.key: 服务私钥pais.internal.mycompany.com.crt: 服务证书由我们的私有CA签名ca.crt: 根CA证书需要和服务器证书一起配置或单独让客户端信任4. 在VCF/NSX ALB负载均衡器上配置证书这是客户端接触到的第一道关卡。我们以VMware NSX Advanced Load BalancerAvi为例它是VCF中常用的负载均衡解决方案。4.1 准备证书文件在Avi中配置证书通常需要将私钥和证书链合并成一个PEM格式的文件。证书链的顺序是你的服务证书在前中间CA证书如果有在中间根CA证书在最后。因为我们用的是自建CA直接签名所以链就是服务证书 根CA证书。# 将服务证书和根CA证书合并成链 cat pais.internal.mycompany.com.crt ca.crt pais_cert_chain.pem # 私钥文件保持独立或者也可以合并进同一个文件Avi支持分开上传 # 对于Avi通常我们上传两个文件包含链的pem文件和独立的私钥key文件。4.2 在NSX ALB控制器上创建SSL证书对象登录到NSX ALB控制器管理界面。导航到模板-安全-SSL/TLS证书。点击创建。证书类型选择“证书”。格式选择“PEM”。证书将pais_cert_chain.pem文件的内容全部复制粘贴进去。私钥将pais.internal.mycompany.com.key文件的内容复制粘贴进去。为证书起一个名字例如ssl-pais-internal。点击保存。踩坑实录2粘贴证书和密钥时务必确保格式完全正确没有多余的空格、换行或不可见字符。特别是私钥必须以-----BEGIN PRIVATE KEY-----开头以-----END PRIVATE KEY-----结尾。我曾经因为从Windows记事本复制粘贴导致格式混乱Avi校验失败排查了很久。4.3 将证书绑定到虚拟服务找到负责PAIS入口流量的虚拟服务Virtual Service。编辑该虚拟服务。在SSL/TLS配置部分启用SSL。在SSL证书下拉框中选择你刚刚创建的ssl-pais-internal。SSL配置文件根据安全要求选择例如可以使用系统默认的“System-Standard”或“System-Standard-PFS”。这决定了加密套件和协议版本。保存配置。此时负载均衡器层面已经配置完成。但如果你直接用浏览器访问https://pais.internal.mycompany.com依然会看到安全警告因为你的电脑还不信任我们自建的根CAMyPrivateRootCA。5. 客户端信任根CA证书这是让警告消失的关键一步。你需要将ca.crt文件安装到所有需要访问PAIS服务的客户端机器的信任根证书存储区。5.1 Windows系统将ca.crt文件复制到Windows客户端。双击ca.crt文件会打开证书查看器。点击安装证书。存储位置选择本地计算机需要管理员权限点击下一步。选择将所有的证书都放入下列存储然后点击浏览。选择受信任的根证书颁发机构点击确定然后下一步。点击完成。会弹出安全警告点击“是”。安装成功后重启浏览器Chrome、Edge使用系统的证书存储再次访问PAIS地址警告应该消失显示为安全的锁标志。5.2 macOS系统将ca.crt文件复制到Mac客户端。双击ca.crt文件这会打开“钥匙串访问”应用。在钥匙串访问中确保左侧选中的是“系统”钥匙串需要输入密码。找到你刚刚导入的证书名称是MyPrivateRootCA双击打开。在“信任”部分将“使用此证书时”设置为“始终信任”。关闭窗口输入密码保存更改。重启Safari或Chrome访问。5.3 Linux系统 (Ubuntu/CentOS)# 将根CA证书复制到系统CA存储目录 sudo cp ca.crt /usr/local/share/ca-certificates/MyPrivateRootCA.crt # 注意文件扩展名必须是 .crt # 更新CA证书存储 sudo update-ca-certificates # 输出应显示Adding debian:MyPrivateRootCA.pem # 验证证书是否被添加 openssl verify /usr/local/share/ca-certificates/MyPrivateRootCA.crt # 应输出/usr/local/share/ca-certificates/MyPrivateRootCA.crt: OK对于使用curl、wget等命令行工具系统更新后即可生效。对于Firefox浏览器它有自己的证书存储需要单独导入打开Firefox设置 - 隐私与安全 - 查看证书 - 证书机构 - 导入选择ca.crt文件勾选“信任由此证书颁发机构标识的网站”确定。5.4 浏览器与命令行工具的差异Chrome/Edge/IE依赖操作系统的证书存储。系统信任了它们就信任。Firefox使用自带的NSS证书库需要单独导入。Java应用使用独立的cacerts信任库。需要将根CA证书导入到JRE的cacerts中使用keytool命令。Pythonrequests库默认使用系统的CA包。在Linux上配置系统存储后通常生效。也可以手动指定verify参数为ca.crt的路径。Docker Client如果Docker守护进程配置了TLS客户端也需要信任相应的CA证书。踩坑实录3团队里一位数据分析师的Python脚本调用PAIS API失败报SSL错误。检查后发现他是在Windows的Anaconda环境里运行而Anaconda可能使用了自带的OpenSSL库没有读取系统证书存储。解决方法是在requests请求中显式指定证书路径requests.get(url, verify‘C:\path\to\ca.crt’)。所以在复杂环境下不能假设所有客户端都自动继承了系统信任。6. PAIS Kubernetes Ingress与内部服务配置负载均衡器处理了外部流量但流量进入K8s集群后还需要经过Ingress。如果PAIS的部署包如Helm Chart要求配置TLS证书通常指的是Ingress TLS。6.1 创建Kubernetes TLS Secret在部署PAIS的Kubernetes命名空间中我们需要创建一个包含证书和私钥的Secret类型为kubernetes.io/tls。# 假设你在部署PAIS的目录下且已配置好kubectl上下文连接到TKG集群 kubectl create namespace pais-production # 创建TLS Secret kubectl create secret tls pais-tls-secret \ --namespacepais-production \ --certpais.internal.mycompany.com.crt \ --keypais.internal.mycompany.com.key重要这里使用的证书和私钥必须与在负载均衡器上配置的证书是同一套。否则会出现“证书不匹配”的错误。负载均衡器可能做SSL终止也可能做SSL透传。如果是终止模式负载均衡器用一套证书Ingress可以用另一套甚至不用。但在我们的自签名场景下为了简化通常让负载均衡器做SSL终止然后将HTTP流量转发给Ingress。这样Ingress就不需要配置TLS了。具体采用哪种模式需要看PAIS的部署说明和负载均衡器的配置。6.2 配置PAIS Helm Chart的Ingress TLS查看PAIS的Helm Chart的values.yaml文件通常会有Ingress相关的配置项ingress: enabled: true className: contour # 或 nginx取决于集群的Ingress Controller hosts: - host: pais.internal.mycompany.com paths: - path: / pathType: Prefix tls: - secretName: pais-tls-secret # 引用我们上面创建的Secret hosts: - pais.internal.mycompany.com在部署时通过--set参数或修改的values.yaml文件来启用这些配置。6.3 服务网格如Istio的证书配置如果启用如果PAIS部署在启用了Istio服务网格的集群中并且开启了严格的mTLS模式那么证书配置会更复杂一层。你需要考虑入口网关Istio IngressGateway证书这相当于替代了原生的Kubernetes Ingress。你需要将证书和私钥配置到Istio的Gateway资源中方式也是通过创建Secret但Secret必须放在istio-system命名空间并且遵循Istio的命名规范如istio-ingressgateway-certs。内部服务间通信证书Istio通常会通过其citadel组件自动为每个服务签发和管理证书。这些证书的根CA是Istio自带的。关键点来了如果你有集群外的客户端如另一个传统VM上的应用需要直接调用PAIS的某个内部服务非通过入口网关并且该服务启用了mTLS那么这个外部客户端就需要信任Istio的根CA证书。你需要从Istio中提取这个根CA证书istio-system命名空间中的istio-ca-secret并将其安装到外部客户端上。踩坑实录4我们有一个位于VCF外部的监控系统需要调用PAIS的某个指标接口。PAIS集群启用了Istio且策略为STRICT。直接调用一直失败。后来发现是mTLS问题。解决方案是要么为该监控服务创建一个ServiceEntry并将其纳入网格要么在目标服务的DestinationRule中为该监控系统的IP设置一个豁免策略使用trafficPolicy.tls.mode: DISABLE但后者安全性降低。最终我们选择了为监控系统安装Istio的根CA证书并配置客户端证书的方式实现了安全的mTLS通信。7. 常见问题排查与调试技巧即使按照步骤操作你可能还是会遇到问题。下面是一个快速排查清单和调试命令。7.1 问题排查清单现象可能原因排查步骤浏览器显示“不是私密连接”1. 根CA证书未安装到客户端。2. 证书域名不匹配SAN配置错误。3. 证书已过期。1. 检查客户端证书存储。2. 用openssl x509 -in cert.crt -text -noout查看证书详情核对SAN和有效期。3. 检查浏览器错误代码如NET::ERR_CERT_AUTHORITY_INVALID。curl报错 “SSL certificate problem: self signed certificate”客户端不信任自签名CA。使用curl --cacert /path/to/ca.crt https://...指定CA证书。如果成功证明是信任问题。curl报错 “SSL certificate problem: certificate has expired”证书过期。检查证书有效期openssl x509 -in cert.crt -enddate -nooutcurl报错 “SSL certificate problem: unable to get local issuer certificate”证书链不完整。服务器没有发送完整的证书链缺少中间CA或根CA。1. 用openssl s_client -connect host:port -showcerts查看服务器发送的完整链。2. 确保负载均衡器或服务器配置中包含了完整的证书链。访问负载均衡器VIP正常但访问Ingress域名报错1. DNS解析问题。2. 负载均衡器到Ingress Controller的健康检查或路由配置错误。3. Ingress Controller未正确配置TLS或后端服务不可用。1.nslookup pais.internal.mycompany.com。2. 检查负载均衡器虚拟服务的池Pool成员状态和健康检查。3. 检查K8s Ingress资源状态kubectl describe ingress name。4. 检查Ingress Controller Pod日志。部分客户端正常部分报错1. 客户端系统/浏览器证书存储未同步更新。2. 客户端应用如Java、Python使用了独立的信任库。3. 客户端有代理或防火墙拦截导致证书验证行为不同。1. 确认报错客户端已正确安装根CA证书并重启了应用。2. 检查特定应用的信任库配置如Java的-Djavax.net.ssl.trustStore。3. 在报错客户端上用openssl s_client进行测试对比与正常客户端的输出差异。7.2 必备调试命令检查证书详细信息openssl x509 -in pais.internal.mycompany.com.crt -text -noout重点关注Subject尤其是CNIssuerValidity起止时间以及最重要的X509v3 Subject Alternative Name部分。模拟客户端连接查看服务器发送的证书链openssl s_client -connect pais.internal.mycompany.com:443 -showcerts这个命令会打印出建立TLS连接的全过程包括服务器返回的所有证书。你可以看到证书链是否完整以及终端实体证书的SAN信息。验证证书链和信任# 使用系统CA存储验证 openssl verify pais.internal.mycompany.com.crt # 使用指定的CA证书验证 openssl verify -CAfile ca.crt pais.internal.mycompany.com.crt检查Kubernetes Secret内容kubectl get secret pais-tls-secret -n pais-production -o yaml # 证书和密钥是Base64编码的可以解码查看 kubectl get secret pais-tls-secret -n pais-production -o jsonpath{.data.tls\.crt} | base64 -d | openssl x509 -text -noout kubectl get secret pais-tls-secret -n pais-production -o jsonpath{.data.tls\.key} | base64 -d | openssl rsa -check -noout7.3 证书过期监控与续订自签名证书最大的运维负担就是续订。证书过期会导致服务突然中断且错误不明显。记录有效期将证书的过期日期记录到日历或监控系统中。自动化续订脚本编写脚本自动化证书续订流程包括生成新CSR、用CA签名、更新负载均衡器和K8s Secret。关键步骤更新Secret后需要重启相关的Pod如Ingress Controller Pod以加载新证书。可以通过给Pod添加注解如kubectl annotate pod pod-name date$(date)来触发滚动更新。使用证书管理工具对于更复杂的环境可以考虑使用cert-manager这样的Kubernetes原生证书管理工具。它可以集成私有CA如step-ca自动为Ingress等资源签发和轮换证书大大减轻管理压力。虽然初始设置复杂但长期来看是更优解。整个配置过程从原理到实操最深的体会就是“细节决定成败”。一个SAN字段的缺失、一个证书链的不完整、一个客户端信任库的遗漏都可能导致连接失败。尤其是在VCF和PAIS这种多层级的云原生环境里清晰地理解流量路径和每一层的安全边界是成功配置自签名TLS证书的关键。建议在正式部署前先在一个简单的测试环境中走通全流程记录下每一步的命令和配置形成属于你们团队的标准化操作手册这会为后续的运维和问题排查带来极大的便利。

相关新闻

本地部署情感对话AI:从环境搭建到API集成的完整实践指南

本地部署情感对话AI:从环境搭建到API集成的完整实践指南

这次我们来看一个名为“我将亲自安慰你”的项目。这个名字听起来很特别,但它本质上是一个专注于情感陪伴与对话的AI应用。在技术层面,它通常意味着一个本地部署的、能够进行多轮情感化对话的语言模型或智能体。对于开发者、AI爱好者或对个性化聊天机器人…

2026/8/2 11:05:23 阅读更多
速卖通AI图片翻译API集成实战

速卖通AI图片翻译API集成实战

问题引入在速卖通平台上,跨国销售的最大挑战之一就是商品图片的多语言适配。当一位卖家准备将200款冬季外套推向西班牙、法国、德国和日本市场时,他面临的困境非常具体:每款产品需要4-6张主图,总计超过1000张图片需要翻译和调整。…

2026/8/2 11:05:23 阅读更多
MNIST数据集下载与预处理全攻略:从入门到工程实践

MNIST数据集下载与预处理全攻略:从入门到工程实践

1. 从“Hello World”到“Hello MNIST”:为什么它依然是机器学习的入门基石 如果你刚开始接触机器学习,或者正准备从理论转向实践,那么“MNIST”这个名字你大概率已经听过无数遍了。它就像一个技术圈的“Hello World”,几乎出现在…

2026/8/2 14:46:16 阅读更多
从Anthropic大会事件看AI服务依赖风险与高可用架构设计

从Anthropic大会事件看AI服务依赖风险与高可用架构设计

1. 项目概述:一场技术发布会的“惊魂时刻” 如果你这几天关注AI圈,大概率被“Fable 5突遭封禁,Anthropic大会差点黄了!”这条消息刷屏了。这听起来像是一场科技发布会的灾难片预告,但背后折射出的,是当前全…

2026/8/2 14:46:16 阅读更多
3分钟搞定!QQ空间历史说说完整备份终极指南

3分钟搞定!QQ空间历史说说完整备份终极指南

3分钟搞定!QQ空间历史说说完整备份终极指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾想过,那些年发过的QQ空间说说,那些记录青春的文字…

2026/8/2 0:04:01 阅读更多
3分钟搞定!QQ空间历史说说完整备份终极指南

3分钟搞定!QQ空间历史说说完整备份终极指南

3分钟搞定!QQ空间历史说说完整备份终极指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾想过,那些年发过的QQ空间说说,那些记录青春的文字…

2026/8/2 0:04:01 阅读更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是应用材料(Applied Materials)公司生产的一款用于半导体设备的I/O信号分配电路板。该型号(0100-02186)的核心特点如下:专用于Endura等半导体工艺腔室。集成信号路由与分配功能。连接控制…

2026/8/2 2:51:21 阅读更多
Nissei Corp FFMN-32L-10-T0 40AX 三相异步电动机

Nissei Corp FFMN-32L-10-T0 40AX 三相异步电动机

Nissei Corp FFMN-32L-10-T0 40AX 三相异步电动机是日本日清(Nissei)品牌的一款工业用三相异步电机,适用于自动化设备及通用机械驱动。该型号(FFMN-32L-10-T0 40AX)的核心特点如下:三相交流异步电动机。额定…

2026/8/2 2:52:49 阅读更多