{"record":{"id":"a6e0bc5aa86102e5","repo":"derailed/k9s","slug":"user-is-not-authorized-to-update-portforward","errorCode":null,"errorMessage":"user is not authorized to update portforward","messagePattern":"user is not authorized to update portforward","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dao/port_forwarder.go","lineNumber":149,"sourceCode":"\t}\n\n\tpodName := strings.Split(n, \"|\")[0]\n\tvar res Pod\n\tres.Init(p, client.PodGVR)\n\tpod, err := res.GetInstance(client.FQN(ns, podName))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif pod.Status.Phase != v1.PodRunning {\n\t\treturn nil, fmt.Errorf(\"unable to forward port because pod is not running. Current status=%v\", pod.Status.Phase)\n\t}\n\n\tauth, err = p.Client().CanI(ns, client.PodGVR.WithSubResource(\"portforward\"), \"\", []string{client.CreateVerb})\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 update portforward\")\n\t}\n\n\tcfg, err := p.Client().RestConfig()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcfg.GroupVersion = &schema.GroupVersion{Group: \"\", Version: \"v1\"}\n\tcfg.APIPath = \"/api\"\n\tcodec, _ := codec()\n\tcfg.NegotiatedSerializer = codec.WithoutConversion()\n\tclt, err := rest.RESTClientFor(cfg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq := clt.Post().\n\t\tResource(\"pods\").\n\t\tNamespace(ns).\n\t\tName(podName).","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/dao/port_forwarder.go#L131-L167","documentation":"After confirming the pod is Running, Start separately authorizes create on the pods/portforward subresource — the same subresource kubectl port-forward uses. Plain pod permissions never imply this subresource, so it must be granted explicitly.","triggerScenarios":"CanI(ns, pods/portforward, \"\", create) false — the role covers pods but omits the portforward subresource.","commonSituations":"RBAC templates that copy pod rules without subresources; cluster policies that deliberately block tunnels (security baselines forbidding port-forward to production); users confused because kubectl get pods works fine.","solutions":["Grant create on the subresource: resources [\"pods/portforward\"] verbs [\"create\"]","Verify: kubectl auth can-i create pods/portforward -n <ns>","If policy forbids tunnels, use an alternative (Service/Ingress, kubectl debug, ephemeral containers)"],"exampleFix":"apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: port-forwarder\n  namespace: default\nrules:\n- apiGroups: [\"\"]\n  resources: [\"pods\", \"pods/portforward\"]\n  verbs: [\"get\", \"create\"]","handlingStrategy":"validation","validationCode":"ok, err := client.CanI(ns, client.PodGVR.WithSubResource(\"portforward\"), \"\", []string{\"create\"})\nif err != nil { return err }\nif !ok { return fmt.Errorf(\"create on pods/portforward denied in %s\", ns) }","typeGuard":null,"tryCatchPattern":"if _, err := pf.Start(path, tunnel); err != nil {\n    if strings.Contains(err.Error(), \"not authorized to update portforward\") {\n        // add create pods/portforward to the role, then retry\n    }\n}","preventionTips":["Never assume pods permissions cover pods/portforward — it is a distinct subresource","Where policy blocks tunnels, wire alternatives (Service expose, kubectl debug) into workflows","Test roles with kubectl auth can-i create pods/portforward before shipping"],"tags":["kubernetes","rbac","port-forward","subresource"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}