diff --git a/apps/rlark/docs/examples/agent-rbac.yaml b/apps/rlark/docs/examples/agent-rbac.yaml index d31c726..b79fe9b 100644 --- a/apps/rlark/docs/examples/agent-rbac.yaml +++ b/apps/rlark/docs/examples/agent-rbac.yaml @@ -1,5 +1,5 @@ # Agent RBAC -# Applied by quickstart.sh to each kind data plane cluster. +# Applied by quickstart.sh and quickstart-dp.sh to each kind data plane cluster. apiVersion: v1 kind: ServiceAccount metadata: @@ -14,6 +14,10 @@ rules: - apiGroups: [""] resources: ["nodes", "pods", "pods/log", "services", "configmaps", "secrets", "namespaces", "persistentvolumeclaims", "events"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +# WebTerminal opens a container session with POST pods/exec. +- apiGroups: [""] + resources: ["pods/exec"] + verbs: ["create"] - apiGroups: ["apps"] resources: ["deployments", "replicasets", "statefulsets", "daemonsets"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] @@ -38,4 +42,4 @@ roleRef: subjects: - kind: ServiceAccount name: rlark-agent - namespace: rlark-system \ No newline at end of file + namespace: rlark-system diff --git a/apps/rlark/docs/user-guide/jobs.md b/apps/rlark/docs/user-guide/jobs.md index f82caf3..1aa90d3 100644 --- a/apps/rlark/docs/user-guide/jobs.md +++ b/apps/rlark/docs/user-guide/jobs.md @@ -147,6 +147,18 @@ You can open an interactive terminal directly into the main container of any run From the Worker list, click **Terminal** on any running Worker. This opens `/bin/bash` by default in the Worker's main container. The browser establishes a WebSocket to Gateway, which proxies the session through Server to Agent and then execs into the container. The user does not need to log in with SSH. +### Troubleshooting Permission Errors + +If the terminal reports `cannot create resource "pods/exec"`, the data-plane Agent's ServiceAccount lacks permission to execute commands in containers. Ask an administrator to grant the Agent `create` access to `pods/exec` in the target data-plane cluster. For quickstart deployments, reapply the updated RBAC manifest from the repository root: + +```bash +kubectl --kubeconfig apply -f apps/rlark/docs/examples/agent-rbac.yaml +kubectl --kubeconfig auth can-i create pods --subresource=exec \ + -n rlark-system --as=system:serviceaccount:rlark-system:rlark-agent +``` + +Once the check returns `yes`, reopen the terminal; no Agent or Worker restart is required. Apply these permissions to the data-plane Kubernetes cluster, not the control-plane kcp instance. + ### Diagnostic Commands Once inside the terminal, you can run diagnostic commands to inspect the container environment: diff --git a/apps/rlark/docs/zh/user-guide/jobs.md b/apps/rlark/docs/zh/user-guide/jobs.md index 8b705f3..d35407a 100644 --- a/apps/rlark/docs/zh/user-guide/jobs.md +++ b/apps/rlark/docs/zh/user-guide/jobs.md @@ -143,6 +143,18 @@ RLark 支持以下任务类型,每种类型预配置了适合该工作负载 在 Worker 列表中点击任意运行中 Worker 的**终端**操作,默认会在其主容器中打开 `/bin/bash`。浏览器通过 WebSocket 连接 Gateway,再由 Gateway 经 Server 代理到 Agent,最终 exec 进入容器;用户无需进行 SSH 登录。 +### 权限错误排查 + +如果终端提示 `cannot create resource "pods/exec"`,说明数据面 Agent 的 ServiceAccount 缺少执行容器命令的权限。请管理员在目标数据面集群为 Agent 授予 `pods/exec` 的 `create` 权限。使用快速开始部署的集群,可以在仓库根目录重新应用更新后的 RBAC 清单: + +```bash +kubectl --kubeconfig <数据面-kubeconfig> apply -f apps/rlark/docs/examples/agent-rbac.yaml +kubectl --kubeconfig <数据面-kubeconfig> auth can-i create pods --subresource=exec \ + -n rlark-system --as=system:serviceaccount:rlark-system:rlark-agent +``` + +确认返回 `yes` 后重新打开终端,无需重启 Agent 或 Worker。该权限配置在数据面 Kubernetes 集群中,不是在控制面的 kcp 中。 + ### 诊断命令 进入终端后可运行诊断命令检查容器环境: diff --git a/apps/rlark/pkg/agent/rbac_test.go b/apps/rlark/pkg/agent/rbac_test.go new file mode 100644 index 0000000..23e3db0 --- /dev/null +++ b/apps/rlark/pkg/agent/rbac_test.go @@ -0,0 +1,77 @@ +package agent + +import ( + "io" + "os" + "slices" + "testing" + + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/kubernetes/scheme" +) + +func TestQuickstartAgentTerminalRBAC(t *testing.T) { + manifest, err := os.Open("../../docs/examples/agent-rbac.yaml") + require.NoError(t, err) + defer func() { require.NoError(t, manifest.Close()) }() + + var account *corev1.ServiceAccount + var role *rbacv1.ClusterRole + var binding *rbacv1.ClusterRoleBinding + decoder := yaml.NewYAMLOrJSONDecoder(manifest, 4096) + for { + var raw runtime.RawExtension + err := decoder.Decode(&raw) + if err == io.EOF { + break + } + require.NoError(t, err) + obj, _, err := scheme.Codecs.UniversalDeserializer().Decode(raw.Raw, nil, nil) + require.NoError(t, err) + switch obj := obj.(type) { + case *corev1.ServiceAccount: + account = obj + case *rbacv1.ClusterRole: + role = obj + case *rbacv1.ClusterRoleBinding: + binding = obj + } + } + require.NotNil(t, account) + require.NotNil(t, role) + require.NotNil(t, binding) + require.Equal(t, "rlark-agent", account.Name) + require.Equal(t, "rlark-system", account.Namespace) + require.Equal(t, rbacv1.RoleRef{APIGroup: rbacv1.GroupName, Kind: "ClusterRole", Name: role.Name}, binding.RoleRef) + require.Contains(t, binding.Subjects, rbacv1.Subject{Kind: "ServiceAccount", Name: account.Name, Namespace: account.Namespace}) + + // handleTerminal uses POST pods/exec. Ordinary Pod access does not grant + // access to this subresource, and exec does not need mutation verbs other + // than create. + for _, tt := range []struct { + verb string + want bool + }{ + {"create", true}, + {"delete", false}, + {"patch", false}, + {"update", false}, + } { + t.Run(tt.verb, func(t *testing.T) { + allowed := false + for _, rule := range role.Rules { + if len(rule.ResourceNames) == 0 && + (slices.Contains(rule.APIGroups, "") || slices.Contains(rule.APIGroups, "*")) && + (slices.Contains(rule.Resources, "pods/exec") || slices.Contains(rule.Resources, "*")) && + (slices.Contains(rule.Verbs, tt.verb) || slices.Contains(rule.Verbs, "*")) { + allowed = true + } + } + require.Equal(t, tt.want, allowed) + }) + } +}