{"record":{"id":"da131aa03d3313bd","repo":"derailed/k9s","slug":"user-is-not-authorized-to-view-pod-logs","errorCode":null,"errorMessage":"user is not authorized to view pod logs","messagePattern":"user is not authorized to view pod logs","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/pod.go","lineNumber":159,"sourceCode":"\t\t\treturn res, fmt.Errorf(\"expecting interface map but got `%T\", o)\n\t\t}\n\t\tif spec[\"nodeName\"] == nodeName {\n\t\t\tres = append(res, &render.PodWithMetrics{Raw: u, MX: pmx[fqn]})\n\t\t}\n\t}\n\n\treturn res, nil\n}\n\n// Logs fetch container logs for a given pod and container.\nfunc (p *Pod) Logs(path string, opts *v1.PodLogOptions) (*restclient.Request, error) {\n\tns, n := client.Namespaced(path)\n\tauth, err := p.Client().CanI(ns, client.NewGVR(client.PodGVR.String()+\":log\"), n, client.GetAccess)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !auth {\n\t\treturn nil, fmt.Errorf(\"user is not authorized to view pod logs\")\n\t}\n\n\tdial, err := p.Client().DialLogs()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn dial.CoreV1().Pods(ns).GetLogs(n, opts), nil\n}\n\n// Containers returns all container names on pod.\nfunc (p *Pod) Containers(path string, includeInit bool) ([]string, error) {\n\tpod, err := p.GetInstance(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcc := make([]string, 0, len(pod.Spec.Containers)+len(pod.Spec.InitContainers))","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/pod.go#L141-L177","documentation":"Pod.Logs authorizes get on the pods/log subresource (GVR pods:log) in the pod's namespace before opening the log stream. RBAC on pods does not imply pods/log — it is a separate subresource — so users who can read pods but were never granted the subresource are rejected here.","triggerScenarios":"CanI(ns, pods:log, <pod>, get) false — the role binds get/list on pods but never lists pods/log under resources.","commonSituations":"Hand-rolled minimal RBAC that forgets the subresource; viewer roles cloned from pod-read templates; break-glass debugging where the user can see pods but not their logs.","solutions":["Extend the role: resources: [\"pods\", \"pods/log\"] verbs: [\"get\"]","Verify: kubectl auth can-i get pods/log -n <namespace>","Keep pods/log separate from pods/exec when designing least-privilege roles"],"exampleFix":"apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: pod-logs-reader\n  namespace: default\nrules:\n- apiGroups: [\"\"]\n  resources: [\"pods\", \"pods/log\"]\n  verbs: [\"get\", \"list\"]","handlingStrategy":"validation","validationCode":"ok, err := client.CanI(ns, \"pods:log\", podName, \"get\")\nif err != nil { return err }\nif !ok { return fmt.Errorf(\"no pods/log access in %s; ask for get on pods/log\", ns) }","typeGuard":null,"tryCatchPattern":"if _, err := podDAO.Logs(path, opts); err != nil {\n    if strings.Contains(err.Error(), \"not authorized to view pod logs\") {\n        // hide log actions for this user instead of retrying\n    }\n}","preventionTips":["Always pair pods with pods/log in read roles you hand out","Preflight with kubectl auth can-i get pods/log -n <ns> before enabling log UI","Keep pods/log grants namespace-scoped unless debugging cluster-wide"],"tags":["kubernetes","rbac","logs","pod","subresource"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}