1. 引言
Helm 是 Kubernetes 的包管理工具,已经成为 DevOps 工具链中的核心组件之一。它简化了在 Kubernetes 集群上部署和管理应用程序的流程。
然而,和所有强大的工具一样,Helm 有时也会抛出一些令人摸不着头脑的错误,例如在执行 helm list
时出现的错误信息:Error: configmaps is forbidden: User “system:serviceaccount:kube-system:default” cannot list configmaps in the namespace “kube-system”。
本文将深入分析该错误的根源,并提供多种解决方案。我们从权限模型(RBAC)出发,逐步探讨不同场景下的解决办法,帮助你快速定位并修复问题。
2. 错误分析
错误信息 configmaps is forbidden: User “system:serviceaccount:kube-system:default” cannot list configmaps in the namespace “kube-system” 明确指出这是一个权限问题。
Kubernetes 使用基于角色的访问控制(RBAC)机制来管理集群资源的访问权限。这意味着,任何用户、服务账户或组件在访问 API 时都必须经过身份认证和授权。
默认情况下,Helm 使用的是 kube-system:default
服务账户,它在 kube-system
命名空间中没有足够的权限来列出 ConfigMap。这种限制是为了安全考虑,避免服务账户拥有不必要的权限。
因此,要解决这个问题,我们需要为 Helm 使用的服务账户授予适当的权限。
3. 初步排查步骤
在尝试解决权限问题之前,先确认几个基础点。
3.1. 验证 Helm 与 Kubernetes 版本
确保 Helm 与 Kubernetes 的版本兼容:
$ helm version
version.BuildInfo{
Version:"v3.13.3",
GitCommit:"3a31588ad33fe3b89af5a2a54ee1d25bfe6eaa5e",
GitTreeState:"clean",
GoVersion:"go1.20.5"
}
$ kubectl version
Client Version: version.Info{
Major:"1",
Minor:"28",
GitVersion:"v1.28.2",
GitCommit:"89a4ea3e1e4ddd7f7572286090859619aa2dc4ba",
GitTreeState:"clean",
BuildDate:"2023-09-13T09:35:49Z",
GoVersion:"go1.20.8",
Compiler:"gc",
Platform:"linux/amd64"
}
Server Version: version.Info{
Major:"1",
Minor:"28",
GitVersion:"v1.28.2",
GitCommit:"89a4ea3e1e4ddd7f7572286090859619aa2dc4ba",
GitTreeState:"clean",
BuildDate:"2023-09-13T09:29:07Z",
GoVersion:"go1.20.8",
Compiler:"gc",
Platform:"linux/amd64"
}
确保 Helm 与 Kubernetes 的版本是兼容的。如果你使用的是 Helm 2,建议尽快升级到 Helm 3。
3.2. 确认 Helm 使用的命名空间
如果 Helm 不在 kube-system
命名空间下运行,你可能需要指定命名空间:
$ helm list --namespace kube-system
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
kube-system-release kube-system 3 2023-06-30 14:00:00.000000 +0000 UTC deployed kube-system-chart-3.0.0 3.0.0
确保 Helm 正确指向了你期望的命名空间。
3.3. 检查 RBAC 是否启用
确认集群是否启用了 RBAC:
$ kubectl api-versions | grep rbac
rbac.authorization.k8s.io/v1
如果输出中包含 rbac.authorization.k8s.io/v1
,说明 RBAC 已启用。
3.4. 查看当前服务账户权限
查看默认服务账户在 kube-system
命名空间中的权限:
$ kubectl auth can-i --list \
--namespace kube-system \
--as system:serviceaccount:kube-system:default
Resources Non-Resource URLs Resource Names Verbs
selfsubjectaccessreviews.authorization.k8s.io [] [] [create]
selfsubjectrulesreviews.authorization.k8s.io [] [] [create]
configmaps [] [] [get list watch]
...
如果 configmaps
的 verbs
包含 get
, list
, watch
,说明该服务账户已有足够权限。否则就需要手动授权。
4. 为默认服务账户授予权限
最直接的解决方案是为 Helm 使用的服务账户添加权限。
4.1. 授予只读权限
如果你只需要查看资源,可以授予 view
权限:
$ kubectl create rolebinding default-view \
--clusterrole=view \
--serviceaccount=kube-system:default \
--namespace=kube-system
rolebinding.rbac.authorization.k8s.io/default-view created
此命令将 view
角色绑定到 kube-system
命名空间下的 default
服务账户,赋予其只读权限。
4.2. 授予管理员权限
如果你需要安装或升级 Chart,可以授予 cluster-admin
权限:
$ kubectl create clusterrolebinding add-on-cluster-admin \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:default
clusterrolebinding.rbac.authorization.k8s.io/add-on-cluster-admin created
⚠️ 注意:这种方式虽然方便,但会赋予服务账户集群管理员权限,存在安全风险。建议根据实际需求授予最小权限。
5. Helm 2 中为 Tiller 创建专用服务账户
如果你仍在使用 Helm 2,建议不要使用默认服务账户,而是为 Tiller 创建一个专用服务账户。
5.1. 创建服务账户
$ kubectl create serviceaccount --namespace kube-system tiller
serviceaccount/tiller created
5.2. 创建 ClusterRoleBinding
$ kubectl create clusterrolebinding tiller-cluster-rule \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:tiller
clusterrolebinding.rbac.authorization.k8s.io/tiller-cluster-rule created
5.3. 初始化 Helm 使用新账户
$ helm init --service-account tiller --upgrade
$HELM_HOME has been configured at /home/user/.helm.
Tiller (the Helm server-side component) has been upgraded to the current version.
Happy Helming!
✅ 优势:比直接使用默认账户更安全,权限更集中。
6. 限制 Helm 2 的访问范围到特定命名空间
在多租户环境中,可以将 Tiller 限制在特定命名空间内运行,以提升安全性。
6.1. 创建新命名空间
$ kubectl create namespace tiller-world
namespace/tiller-world created
6.2. 创建服务账户
$ kubectl create serviceaccount tiller --namespace tiller-world
serviceaccount/tiller created
6.3. 定义 Role
创建文件 role-tiller.yaml
:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: tiller-manager
namespace: tiller-world
rules:
- apiGroups: ["", "batch", "extensions", "apps"]
resources: ["*"]
verbs: ["*"]
应用该角色:
$ kubectl create -f role-tiller.yaml
role.rbac.authorization.k8s.io/tiller-manager created
6.4. 创建 RoleBinding
创建文件 rolebinding-tiller.yaml
:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: tiller-binding
namespace: tiller-world
subjects:
- kind: ServiceAccount
name: tiller
namespace: tiller-world
roleRef:
kind: Role
name: tiller-manager
apiGroup: rbac.authorization.k8s.io
应用该绑定:
$ kubectl create -f rolebinding-tiller.yaml
rolebinding.rbac.authorization.k8s.io/tiller-binding created
6.5. 初始化 Helm 使用新命名空间
$ helm init \
--service-account tiller \
--tiller-namespace tiller-world
$HELM_HOME has been configured at /home/user/.helm.
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Happy Helming!
6.6. 设置环境变量
$ export TILLER_NAMESPACE=tiller-world
✅ 优势:Tiller 仅在指定命名空间内操作,避免权限泛滥。
7. 升级到 Helm 3 以移除 Tiller
Helm 3 引入了客户端无服务器架构,彻底移除了 Tiller 组件,简化了部署流程并提升了安全性。
如果你还在使用 Helm 2,建议尽快升级。
安装 Helm 3
# Linux 示例
$ curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
$ chmod 700 get_helm.sh
$ ./get_helm.sh
使用 Helm 2to3 插件迁移
$ helm plugin install https://github.com/helm/helm-2to3
$ helm 2to3 convert <release_name>
✅ 优势:无 Tiller、无需复杂权限配置、更安全。
8. 总结
方案 | 是否推荐 | 说明 |
---|---|---|
赋予默认服务账户 view 权限 |
✅ | 简单有效,适合只读需求 |
赋予 cluster-admin 权限 |
⚠️ | 快速但存在安全风险 |
为 Tiller 创建专用服务账户 | ✅ | Helm 2 场景推荐 |
限制 Tiller 到特定命名空间 | ✅✅ | 提升安全性,适合多租户 |
升级到 Helm 3 | ✅✅✅ | 最推荐方案,无 Tiller、权限更简洁 |
如果你在使用 Helm 时遇到类似权限问题,建议优先考虑使用 Helm 3 或为 Tiller 创建专用服务账户。避免直接赋予默认服务账户过高的权限,遵循最小权限原则是保障 Kubernetes 安全的最佳实践。