Change:
As the RBAC role need to be related to resources. I think we could use a command to get the supported resources. ref to
This would be cool.
I thought we a command that listed resources in the discover doc a long time ago.
is just the versions, but principle is the same. We want to list all the types, their resources, and tie that back to "explain".
What's the best way to determine this information currently? I'm having difficulty figuring out the exact set of permissions (and how they would be written in an RBAC role) for any given kubectl command. The documentation for this right now is split across multiple places and certain things are not explained at all. Specifically, it's difficult to determine which "API verb" is used for which operations. Take as an example. It's unclear if the way to allow this is to use the "proxy" subresource of a pod or service with "get"/"create"/etc. verbs, or to use the "proxy" verb with the resource (pod, service) directly. is a similar case. The almost works for this purpose, but it's still difficult. Operations for a given resource are grouped into categories like write, read, status, and proxy, but these things don't obviously correlate with API verbs. Again, proxy is especially confusing as there is no mention of a proxy "verb". The API operations are only shown using their HTTP verbs. One thing that could help on this document would be a section on the right column under "kubectl command" that shows exactly the rule needed in an RBAC role to allow this command via kubectl. And even then, that assumes an exact 1-to-1 mapping between API endpoints and kubectl commands, which I doubt is always the case. (For example, port fowarding to a pod seems to require both a GET on the pod resource and a CREATE on a port forward subresource.) There also needs to be better documentation about how this information could have been determined in the first place. I've resorted to manually looking through API requests made with but even then it's difficult to figure out. Amusingly, I was the one who wrote which is referenced in the original issue description (as well as the table explaining verbs in ). tl;dr: It's too difficult right now to go from "I want a user to be able to run " to "here is the RBAC rule to use for that" for any case where there isn't a specific example shown in the docs.
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. Prevent issues from auto-closing with an comment. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
It seem that relative PR stop updated. If this issue still valuable, i will help fix it
Stale issues rot after 30d of inactivity. Mark the issue as fresh with . Rotten issues close after an additional 30d of inactivity. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle rotten /remove-lifecycle stale
Rotten issues close after 30d of inactivity. Reopen the issue with . Mark the issue as fresh with . Send feedback to sig-testing, kubernetes/test-infra and/or . /close

Discussion:
docs/man/man1/kubectl-alpha-diff.1 docs/man/man1/kubectl-alpha.1 docs/man/man1/kubectl-annotate.1 <ins> docs/man/man1/kubectl-api-resources.1 </ins> docs/man/man1/kubectl-api-versions.1 docs/man/man1/kubectl-apply-edit-last-applied.1 docs/man/man1/kubectl-apply-set-last-applied.1

docs/user-guide/kubectl/kubectl_alpha.md docs/user-guide/kubectl/kubectl_alpha_diff.md docs/user-guide/kubectl/kubectl_annotate.md <ins> docs/user-guide/kubectl/kubectl_api-resources.md </ins> docs/user-guide/kubectl/kubectl_api-versions.md docs/user-guide/kubectl/kubectl_apply.md docs/user-guide/kubectl/kubectl_apply_edit-last-applied.md

docs/yaml/kubectl/kubectl.yaml docs/yaml/kubectl/kubectl_alpha.yaml docs/yaml/kubectl/kubectl_annotate.yaml <ins> docs/yaml/kubectl/kubectl_api-resources.yaml </ins> docs/yaml/kubectl/kubectl_api-versions.yaml docs/yaml/kubectl/kubectl_apply.yaml docs/yaml/kubectl/kubectl_attach.yaml

<ins> This file is autogenerated, but we've stopped checking such files into the repository to reduce the need for rebases. Please run hack/generate-docs.sh to populate this file. </ins>

# Cluster Role # ################ <ins> kubectl "${kube_flags[@]}" api-resources </ins> if kube::test::if_supports_resource "${clusterroles}" ; then record_command run_clusterroles_tests fi

srcs = [ "alpha.go", "annotate.go", <ins> "apiresources.go", </ins> "apiversions.go", "apply.go", "apply_edit_last_applied.go",

<ins> /* Copyright 2018 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package cmd import ( "fmt" "io" "sort" "strings" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/printers" ) var ( apiresources_example = templates.Examples(` # Print the supported API Resources kubectl api-resources # Print the supported API Resources with more information kubectl api-resources -o wide # Print the supported namespaced resources kubectl api-resources --namespaced=true # Print the supported non-namespaced resources kubectl api-resources --namespaced=false # Print the supported API Resources with specific APIGroup kubectl api-resources --api-group=extensions`) ) // ApiResourcesOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of // referencing the cmd.Flags() type ApiResourcesOptions struct { out io.Writer Output     string APIGroup   string Namespaced bool NoHeaders  bool } // groupResource contains the APIGroup and APIResource type groupResource struct { APIGroup    string APIResource metav1.APIResource } func NewCmdApiResources(f cmdutil.Factory, out io.Writer) *cobra.Command { options := &ApiResourcesOptions{ out: out, } cmd := &cobra.Command{ Use:     "api-resources", Short:   "Print the supported API resources on the server", Long:    "Print the supported API resources on the server", Example: apiresources_example, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(options.Complete(cmd)) cmdutil.CheckErr(options.Validate(cmd)) cmdutil.CheckErr(options.RunApiResources(cmd, f)) }, } cmdutil.AddOutputFlags(cmd) cmdutil.AddNoHeadersFlags(cmd) cmd.Flags().StringVar(&options.APIGroup, "api-group", "", "The API group to use when talking to the server.") cmd.Flags().BoolVar(&options.Namespaced, "namespaced", true, "Namespaced indicates if a resource is namespaced or not.") return cmd } func (o *ApiResourcesOptions) Complete(cmd *cobra.Command) error { o.Output = cmdutil.GetFlagString(cmd, "output") o.NoHeaders = cmdutil.GetFlagBool(cmd, "no-headers") return nil } func (o *ApiResourcesOptions) Validate(cmd *cobra.Command) error { validOutputTypes := sets.NewString("", "json", "yaml", "wide", "name", "custom-columns", "custom-columns-file", "go-template", "go-template-file", "jsonpath", "jsonpath-file") supportedOutputTypes := sets.NewString("", "wide") outputFormat := cmdutil.GetFlagString(cmd, "output") if !validOutputTypes.Has(outputFormat) { return fmt.Errorf("output must be one of '' or 'wide': %v", outputFormat) } if !supportedOutputTypes.Has(outputFormat) { return fmt.Errorf("--output %v is not available in kubectl api-resources", outputFormat) } return nil } func (o *ApiResourcesOptions) RunApiResources(cmd *cobra.Command, f cmdutil.Factory) error { w := printers.GetNewTabWriter(o.out) defer w.Flush() discoveryclient, err := f.DiscoveryClient() if err != nil { return err } // Always request fresh data from the server discoveryclient.Invalidate() lists, err := discoveryclient.ServerPreferredResources() if err != nil { return err } resources := []groupResource{} groupChanged := cmd.Flags().Changed("api-group") nsChanged := cmd.Flags().Changed("namespaced") for _, list := range lists { if len(list.APIResources) == 0 { continue } gv, err := schema.ParseGroupVersion(list.GroupVersion) if err != nil { continue } for _, resource := range list.APIResources { if len(resource.Verbs) == 0 { continue } // filter apiGroup if groupChanged && o.APIGroup != gv.Group { continue } // filter namespaced if nsChanged && o.Namespaced != resource.Namespaced { continue } resources = append(resources, groupResource{ APIGroup:    gv.Group, APIResource: resource, }) } } if o.NoHeaders == false { if err = printContextHeaders(w, o.Output); err != nil { return err } } sort.Stable(sortableGroupResource(resources)) for _, r := range resources { if o.Output == "wide" { if _, err := fmt.Fprintf(w, "%st%st%st%vt%st%vn", r.APIResource.Name, strings.Join(r.APIResource.ShortNames, ","), r.APIGroup, r.APIResource.Namespaced, r.APIResource.Kind, r.APIResource.Verbs); err != nil { return err } } else { if _, err := fmt.Fprintf(w, "%st%st%st%vt%sn", r.APIResource.Name, strings.Join(r.APIResource.ShortNames, ","), r.APIGroup, r.APIResource.Namespaced, r.APIResource.Kind); err != nil { return err } } } return nil } func printContextHeaders(out io.Writer, output string) error { columnNames := []string{"NAME", "SHORTNAMES", "APIGROUP", "NAMESPACED", "KIND"} if output == "wide" { columnNames = append(columnNames, "VERBS") } _, err := fmt.Fprintf(out, "%sn", strings.Join(columnNames, "t")) return err } type sortableGroupResource []groupResource func (s sortableGroupResource) Len() int      { return len(s) } func (s sortableGroupResource) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s sortableGroupResource) Less(i, j int) bool { ret := strings.Compare(s[i].APIGroup, s[j].APIGroup) if ret > 0 { return false } else if ret == 0 { return strings.Compare(s[i].APIResource.Name, s[j].APIResource.Name) < 0 } return true } </ins>

cmds.AddCommand(NewCmdPlugin(f, in, out, err)) cmds.AddCommand(NewCmdVersion(f, out)) cmds.AddCommand(NewCmdApiVersions(f, out)) <ins> cmds.AddCommand(NewCmdApiResources(f, out)) </ins> cmds.AddCommand(NewCmdOptions(out)) return cmds