Argo CD Web-based Terminal 完整实战指南:在浏览器中安全启用 Pod 远程终端
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
Argo CD 自 v2.4 起内置了基于 Web 的终端功能,让你能像使用kubectl exec一样,直接在浏览器里进入受管 Pod 内获取一个 shell,并完整支持 ANSI 颜色输出,体验上等同于从浏览器发起的 SSH。本文以官方文档为主线,结合仓库源码,从启用配置、Kubernetes 1.31 前后的 RBAC 权限差异、允许 shell 的定制,到终端请求的底层调用链与安全边界,给出可直接落地的完整方案。
功能概述:浏览器里的kubectl exec
Web-based Terminal 是 Argo CD 提供的一项内置于 UI 的能力:只要 Pod 被某个 Application 管理,且当前用户对该 Application 具备exec/create权限,就可以从 Argo CD Web UI 的 Pod 详情页进入一个交互式 shell。它与kubectl exec的语义基本一致,但默认处于禁用状态,这是出于安全考虑。
需要注意这是一个高特权能力:它允许用户在其有权管理的任意 Pod 上执行任意代码。如果该 Pod 挂载了 ServiceAccount 令牌(这是 Kubernetes 的默认行为),那么终端用户实际上就获得了与该 ServiceAccount 相同的权限。因此,在启用该功能之前,务必先完成下文的权限评估与最小化授权设计。
从源码结构看,该功能的完整实现位于 server/application/terminal.go,HTTP 路由在 server/server.go 中注册为/terminal,UI 侧由 pod-terminal-viewer.tsx 负责渲染终端页面。
启用终端
启用 Web Terminal 只需要两个步骤:
1. 修改argocd-cmConfigMap
在argocd-cmConfigMap 中设置exec.enabled键为"true":
apiVersion: v1 kind: ConfigMap metadata: name: argocd-cm namespace: <namespace> # 替换为你的实际命名空间 data: exec.enabled: "true"2. 重启 Argo CD
修改配置后需要重启 Argo CD(使argocd-server重新加载配置)。更推荐的做法是使用kubectl rollout restart滚动重启:
kubectl rollout restart deployment argocd-server -n <namespace>配置在源码中如何被解析
exec.enabled与exec.shells的解析逻辑位于 util/settings/settings.go:settings.ExecEnabled仅在配置值严格等于字符串"true"时为真;exec.shells则按逗号切分为字符串切片。exec.enabled的默认值在官方示例配置 docs/operator-manual/argocd-cm.yaml 中为"false",与文档"默认禁用"的描述一致。
Kubernetes 1.31 前后的权限差异
是否需要额外的集群级 RBAC,取决于目标集群的 Kubernetes 版本:
- Kubernetes 1.31 及以上:
get权限本身已足以 exec 进入容器,因此无需额外权限,直接开启即可使用。 - Kubernetes 1.31 之前:必须额外配置 RBAC 权限,分两步:
第一步:为argocd-server授予 exec 权限
以命名空间(namespaced)或集群(clustered)方式部署的 Argo CD,需要分别 patchargocd-server的 Role 或 ClusterRole,允许其create类型为pods/exec的资源:
- apiGroups: - "" resources: - pods/exec verbs: - create如果希望用命令式方式执行 patch,可以使用以下命令:
- 命名空间部署(namespaced Argo CD):
kubectl patch role <argocd-server-role-name> -n argocd --type='json' -p='[{"op": "add", "path": "/rules/-", "value": {"apiGroups": ["*"], "resources": ["pods/exec"], "verbs": ["create"]}}]'- 集群部署(clustered Argo CD):
kubectl patch clusterrole <argocd-server-clusterrole-name> --type='json' -p='[{"op": "add", "path": "/rules/-", "value": {"apiGroups": ["*"], "resources": ["pods/exec"], "verbs": ["create"]}}]'注意:上述 JSON patch 中的"path": "/rules/-"表示向规则数组追加一条新规则,<argocd-server-role-name>与<argocd-server-clusterrole-name>需要替换为实际名称(通常为argocd-server)。
第二步:为用户授予exec资源权限
在 Argo CD 自身的 RBAC 策略中添加规则,允许用户createexec资源,即:
p, role:myrole, exec, create, */*, allow这条规则既可以添加到argocd-cmConfigMap 的policy.csv中,也可以添加到某个 AppProject 的rbac配置中(例如仅允许在特定项目内使用终端)。关于exec资源的完整语义,参见 RBAC 配置文档。
深入理解exec资源与 RBAC 授权模型
exec是 Argo CD RBAC 中的一个应用级(Application-Specific)资源,详细定义见 docs/operator-manual/rbac.md:当授予create动作时,该策略允许用户通过 Argo CD UI 进入某个应用的 Pod,功能与kubectl exec类似。
这背后的双重校验逻辑可以在 server/application/terminal.go 中看到:处理终端请求时,服务端会依次强制校验
applications资源的get动作(用户必须能读取该 Application);exec资源的create动作(用户必须拥有执行权限)。
也就是说,仅有exec/create而没有对应用的get权限也无法使用终端,两个条件缺一不可。策略中的对象格式为<app-project>/<app-name>,因此可以做到非常细粒度的控制,例如:
# 仅允许 myrole 在 dev-project 项目下进入应用 Pod p, role:myrole, exec, create, dev-project/*, allow修改允许的 shell 列表
默认情况下,Argo CD 会按以下顺序尝试启动 shell:
bashshpowershellcmd
如果所有这些 shell 在目标容器中都不存在,终端会话将失败。如需增加或调整允许的 shell,修改argocd-cmConfigMap 中的exec.shells键,以逗号分隔:
data: exec.shells: "bash,sh,powershell,cmd,zsh,ash"官方示例配置 docs/operator-manual/argocd-cm.yaml 也给出了同样的默认值。从源码看,util/settings/settings.go 将exec.shells按逗号拆分为列表;当配置为空时回退到默认的["bash", "sh", "powershell", "cmd"]。
服务端如何选择 shell
在 server/application/terminal.go 中,shell 的选择逻辑是:如果客户端请求中携带的shell参数位于允许列表内,则直接使用它;否则按允许列表的顺序逐个尝试启动,直到某个 shell 启动成功或全部失败。这种"逐个尝试"的设计保证了在容器只装有sh而没有bash时,终端依然可用。
底层实现解析:一次终端会话的完整链路
理解源码有助于排查问题和评估风险。一次浏览器终端请求在服务端的完整处理流程如下:
路由与鉴权中间件:
/terminal路由在 server/server.go 注册,并包裹了WithAuthMiddleware(会话认证),随后进入WithFeatureFlagMiddleware——如果exec.enabled未开启,直接返回404(见 terminal.go)。参数校验:
pod、container、appName、projectName、namespace等查询参数缺一不可(terminal.go),所有名称都会经过合法性校验,防止注入。命名空间与 RBAC 校验:校验应用命名空间是否在启用范围内(
security.IsNamespaceEnabled),再依次强制校验applications/get与exec/create(terminal.go)。资源归属校验:通过应用资源树(Resource Tree)确认目标 Pod 确实属于该 Application,且目标容器处于Running状态(普通容器或 init 容器均可),见 terminal.go 中的
podExists与containerRunning。建立 exec 连接:
startProcess构造pods/exec子资源请求,使用remotecommand.NewSPDYExecutor建立流;默认还会尝试 WebSocket 执行器,并在失败时通过NewFallbackExecutor回退到 SPDY(terminal.go),这一机制与kubectl exec的 fallback 行为一致。会话保活:会话建立后,每隔 5 秒通过 WebSocket 发送一次 ping,防止负载均衡器因空闲而断开长连接(terminal.go)。
从部署角度看,终端请求经由argocd-server转发到目标集群的 API Server,因此argocd-server必须具有访问目标集群并执行pods/exec的权限——这正是上文 Kubernetes <1.31 需要额外 RBAC 的根本原因。
安全建议与最小化授权实践
由于 Web Terminal 允许在 Pod 内执行任意代码,启用前应认真评估以下安全边界:
- 默认关闭:保持
exec.enabled: "false"(默认值),仅在明确需要时开启。 - 按需授权:使用应用级 RBAC 将
exec/create限制到最小范围,例如只授权给指定角色、指定项目(<project>/*)甚至指定应用(<project>/<app>),避免使用*/*通配授权。 - 了解 ServiceAccount 提权风险:Pod 若挂载 ServiceAccount 令牌,终端用户将获得与该 SA 等同的集群权限,属于事实上的权限提升通道,应结合 Kubernetes 侧的
automountServiceAccountToken: false、Pod Security Admission 等机制综合加固。 - 版本感知:Kubernetes 1.31 及以上版本中,
get权限即足以 exec 进容器,意味着"能读应用信息"的用户可能顺带获得终端能力,需要更谨慎地评估只读用户的授权范围。 - 审计:终端会话会在服务端日志中记录应用、用户名、容器、Pod 与命名空间信息(见 terminal.go 与
terminal session starting日志),可接入日志系统进行审计追踪。
常见问题速查
| 现象 | 原因与排查方向 |
|---|---|
| 访问终端提示 404 | exec.enabled未设置为"true",或配置修改后未重启argocd-server |
| 提示未授权(Unauthorized) | 缺少applications/get或exec/create权限,检查argocd-cm/ AppProject 中的 RBAC 策略 |
| 终端连接失败 | 目标 Pod/容器不存在、容器未处于 Running 状态,或目标 Pod 不属于当前 Application |
| shell 无法启动 | 容器内没有exec.shells列表中的任何 shell,向列表中添加目标容器实际存在的 shell(如ash) |
| Kubernetes <1.31 下无法 exec | argocd-server的 Role/ClusterRole 缺少pods/exec的create权限 |
相关文档与源码导航
- 官方 RBAC 文档:docs/operator-manual/rbac.md
- 配置示例:docs/operator-manual/argocd-cm.yaml
- 终端处理核心实现:server/application/terminal.go
- 配置解析逻辑:util/settings/settings.go
- 路由注册与鉴权:server/server.go
- UI 终端组件:ui/src/app/applications/components/pod-terminal-viewer/pod-terminal-viewer.tsx
【免费下载链接】argo-cdDeclarative Continuous Deployment for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ar/argo-cd
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考