GCP私有实例集成diagrams.net与PlantUML认证问题解决
2025-03-08 03:39:26
搞定 GCP 私有实例上 diagrams.net 与 PlantUML 集成的认证问题
直接说问题,在 Google Cloud Platform (GCP) 上部署 diagrams.net 和 PlantUML,想把它们集成起来,结果认证这块儿卡住了。俩容器(应用容器和 PlantUML 容器),认证不通过,集成用不了。
问题根源在哪?
这事儿多半和下面几个原因有关:
-
跨域资源共享 (CORS) 限制: diagrams.net(JavaScript 客户端)尝试直接向 PlantUML 容器发送请求。因为两个服务不在同一个“域”(通常是不同的端口或不同的主机名),浏览器出于安全考虑,会阻止这种跨域请求。
-
服务间认证缺失/错误: GCP 上的服务通常需要正确的身份验证和授权才能互相通信。 如果 diagrams.net 应用没有以 PlantUML 服务可识别和接受的方式进行身份验证,请求就会被拒绝。
-
网络配置问题 :例如防火墙规则或者内部网络的访问问题等,都可能会导致容器直接互相通信失败
-
PlantUML 容器配置问题 : PlantUML 容器可能没有正确配置来处理来自外部的请求,或者没有启用必要的认证机制。
解决方案
试试下面几个法子,总有一个适合你:
1. 使用反向代理 (推荐)
这是最常用的解决方案。在俩容器前面架一个反向代理(比如 Nginx 或 Envoy),让所有请求都通过代理来转发。
-
原理: 反向代理作为“中间人”,接收来自 diagrams.net 的请求,处理认证,然后将请求转发给 PlantUML 容器,再把 PlantUML 的响应返回给 diagrams.net。这样就绕过了浏览器的 CORS 限制,也简化了服务间认证。
-
步骤 (以 Nginx 为例):
-
创建 Nginx 配置文件:
server { listen 80; server_name your-diagrams-net-domain.com; # 替换成你的域名 location / { proxy_pass http://diagrams-net-app:8080; # 假设 diagrams.net 应用在 8080 端口 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /plantuml/ { proxy_pass http://plantuml-container:8080; # 假设 PlantUML 容器在 8080 端口 proxy_set_header Host $host; #以下两项配置可以在反向代理上添加对所有 /plantuml/ 流量的基本HTTP认证支持。如果您的plantuml-container有特别安全需要,这可能是一种额外的保护手段 # auth_basic "Restricted Access"; #可选,开启 basic 认证 # auth_basic_user_file /etc/nginx/.htpasswd; # 可选, 用户密码文件,需自己用htpasswd生成. # 为GCP 服务间认证准备header (根据实际情况调整) proxy_set_header Authorization "Bearer $(gcloud auth print-identity-token)"; } }
-
部署 Nginx 容器: 将 Nginx 配置文件包含在你的 Docker 镜像中,或者作为 ConfigMap 挂载到 Kubernetes pod 中。
-
更新 diagrams.net 配置: 修改 diagrams.net 的 PlantUML 服务器地址为
/plantuml/
(即 Nginx 代理的路径)。
-
-
安全建议:
- 如果需要更高级的认证,可以考虑在 Nginx 中配置 OAuth 2.0 或 OpenID Connect。
- 确保 Nginx 与 PlantUML 容器之间的通信使用安全的网络(比如 VPC 内部网络)。
gcloud auth print-identity-token
生成的token有时效,此方法仅限开发测试环境。
-
进阶
可以在Nginx中启用缓存,对于经常使用的PlantUML图形请求做加速。
2. 在GCP使用 服务账户进行服务间验证
如果你不想引入额外的反向代理,可以使用GCP提供的内置服务账户进行服务间验证
-
原理 diagrams.net应用所在的容器,应使用某个具有特定权限的服务账户。通过此账户,拿到token,从而被授权能调用plantuml的API。
-
步骤
1. 创建plantuml服务的专用服务账户
创建一个用于plantuml的服务账户,给此服务账户授权,使它能处理请求
2. diagram.net app的服务账户
给予diagrams.net应用服务账户权限。让其能调用Cloud Run Admin API 或者类似能认证其他服务的权限(这取决于plantuml运行的位置,是cloud run还是compute engine)
3. diagrams.net 应用容器中获取token
可以通过google-auth-library
或者 直接使用metadata server 去拿到token,并且,在向plantuml容器发起请求的时候把token加入请求头里
4. 在 PlantUML 服务中验证令牌: PlantUML 服务需要能够验证接收到的身份令牌。 -
示例代码 (Node.js, 获取身份令牌):
const {GoogleAuth} = require('google-auth-library'); async function getAuthToken() { const auth = new GoogleAuth(); const url = 'http://plantuml-container:8080';//plantuml 内部地址 const client = await auth.getIdTokenClient(url); //这里已经实现了目标受众群体的token生成过程。 const res = await client.request({url}); //用拿到的客户端身份,随便发送一次请求。仅仅为了拿token演示。 console.log("==============="); console.info(res.config.headers.Authorization) } getAuthToken();
-
进阶
客户端(这里指diagrams.net )的Token自动刷新逻辑,必须有效处理,因为token会过期. google-auth-library会帮助你搞定这个,只要保持client 对象存活.
3. 调整 CORS 配置(如果 PlantUML 容器允许)
如果 PlantUML 容器的 Web 服务器允许修改 CORS 配置,你可以直接设置允许 diagrams.net 的来源进行跨域访问。 但大多数生产环境下,不建议你这样做
-
原理: PlantUML 服务器返回的 HTTP 响应头中包含
Access-Control-Allow-Origin
字段,指定允许访问的域名。 -
操作 (取决于 PlantUML 的 Web 服务器,以 Tomcat 为例):
在web.xml
内添加filter.<filter> <filter-name>CorsFilter</filter-name> <filter-class>org.apache.catalina.filters.CorsFilter</filter-class> <init-param> <param-name>cors.allowed.origins</param-name> <param-value>https://your-diagrams-net-domain.com</param-value> <!-- 允许的 diagrams.net 域名 --> </init-param> <init-param> <param-name>cors.allowed.methods</param-name> <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value> </init-param> <init-param> <param-name>cors.allowed.headers</param-name> <param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization</param-value> </init-param> </filter> <filter-mapping> <filter-name>CorsFilter</filter-name> <url-pattern>/*</url-pattern> <!--应用到所有url --> </filter-mapping>
-
风险点: 不要把
cors.allowed.origins
设置为*
,除非你的 PlantUML 服务是完全公开的。这会允许任何网站跨域访问你的 PlantUML 服务。 -
局限: 如果plantuml根本不提供给你修改CORS的手段, 那这个方法就无法使用了
4. 如果上述都受限:JSONP(不推荐,仅作备选)
JSONP 是一种古老的绕过跨域限制的方法,但现在已经很少使用。它利用了 <script>
标签可以跨域加载资源的特性。
- 原理: PlantUML 服务需要支持 JSONP 格式的响应。 diagrams.net 通过动态创建一个
<script>
标签,src
属性指向 PlantUML 服务的一个特殊 URL,并携带一个回调函数名。PlantUML 服务返回一段 JavaScript 代码,这段代码会调用指定的回调函数,并将数据作为参数传递。 - 非常不推荐: JSONP 只支持 GET 请求,而且安全性较差,容易受到 XSS 攻击。不到万不得已,别用。这里不提供操作步骤了.
###总结:
按照实际项目环境,老老实实走前两种方式(反向代理和GCP服务账户认证)。如果还有困难, 请详细检查配置,一步一步debug,或考虑GCP支持服务.