Change:
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks! If the matter is security related, please disclose it privately via --What you expected to happen: if returns true I expect to be able to perform the action without issue. Note in this case my service user has a rolebinding in a single namespace (and that is also what my kubecontext is set to.) if I change my default to a different namespace then the command returns false How to reproduce it (as minimally and precisely as possible): create a namespace (test) create a service account in that namespace create a role that gives get list and watch permissions to create a rolebinding from that role to the service account. Anything else we need to know?: this is special because namespaces are not scoped to a namespace. if you replace the command with then you get the exepcted result however this breaks the path of least suprise. Environment: Kubernetes version (use ):Cloud provider or hardware configuration: GKE OS (e.g: ): Kernel (e.g. ): Install tools: Others:
/sig auth
asks the authorization system if the given verb can be performed on the given noun at the given scope. It does not interpret whether the resource exists at that scope. We could warn if we find the specified resource and it does not exist at the specified scope (just like we warn if you ask about a resource that we can't find), but we would still interrogate the authorization system and return the results as we do today. /kind feature /remove-kind bug
/cc

Discussion:
"//staging/src/k8s.io/cli-runtime/pkg/genericclioptions:go_default_library", "//staging/src/k8s.io/cli-runtime/pkg/printers:go_default_library", "//staging/src/k8s.io/cli-runtime/pkg/resource:go_default_library", <ins> "//staging/src/k8s.io/client-go/discovery:go_default_library", </ins> "//staging/src/k8s.io/client-go/kubernetes/typed/authorization/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/rbac/v1:go_default_library",

"k8s.io/apimachinery/pkg/runtime/schema" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/cli-runtime/pkg/genericclioptions" <ins> discovery "k8s.io/client-go/discovery" </ins> authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" describeutil "k8s.io/kubernetes/pkg/kubectl/describe/versioned"

// CanIOptions 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 CanIOptions struct { <del> AllNamespaces bool Quiet         bool NoHeaders     bool Namespace     string AuthClient    authorizationv1client.AuthorizationV1Interface </del> <ins> AllNamespaces   bool Quiet           bool NoHeaders       bool Namespace       string AuthClient      authorizationv1client.AuthorizationV1Interface DiscoveryClient discovery.DiscoveryInterface </ins> Verb           string Resource       schema.GroupVersionResource

return err } o.AuthClient = client.AuthorizationV1() <ins> o.DiscoveryClient = client.Discovery() </ins> o.Namespace = "" if !o.AllNamespaces { o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()

if o.Resource != (schema.GroupVersionResource{}) || o.ResourceName != "" { return fmt.Errorf("NonResourceURL and ResourceName can not specified together") } <ins> } else if !o.Resource.Empty() && !o.AllNamespaces && o.DiscoveryClient != nil { if namespaced, err := isNamespaced(o.Resource, o.DiscoveryClient); err == nil && !namespaced { if len(o.Resource.Group) == 0 { fmt.Fprintf(o.ErrOut, "Warning: resource '%s' is not namespace scopedn", o.Resource.Resource) } else { fmt.Fprintf(o.ErrOut, "Warning: resource '%s' is not namespace scoped in group '%s'n", o.Resource.Resource, o.Resource.Group) } } </ins> } if o.NoHeaders {

} return nil } <ins> func isNamespaced(gvr schema.GroupVersionResource, discoveryClient discovery.DiscoveryInterface) (bool, error) { if gvr.Resource == "*" { return true, nil } apiResourceList, err := discoveryClient.ServerResourcesForGroupVersion(schema.GroupVersion{ Group: gvr.Group, Version: gvr.Version, }.String()) if err != nil { return true, err } for _, resource := range apiResourceList.APIResources { if resource.Name == gvr.Resource { return resource.Namespaced, nil } } return false, fmt.Errorf("the server doesn't have a resource type '%s' in group '%s'", gvr.Resource, gvr.Group) } </ins>

output_message=$(kubectl auth can-i get pods --subresource=log --quiet 2>&1 "${kube_flags[@]}"; echo $?) kube::test::if_has_string "${output_message}" '0' <ins> # kubectl auth can-i get '*' does not warn about namespaced scope or print an error output_message=$(kubectl auth can-i get '*' 2>&1 "${kube_flags[@]}") kube::test::if_has_not_string "${output_message}" "Warning" # kubectl auth can-i get foo does not print a namespaced warning message, and only prints a single lookup error output_message=$(kubectl auth can-i get foo 2>&1 "${kube_flags[@]}") kube::test::if_has_string "${output_message}" "Warning: the server doesn't have a resource type 'foo'" kube::test::if_has_not_string "${output_message}" "Warning: resource 'foo' is not namespace scoped" # kubectl auth can-i get pods does not print a namespaced warning message or a lookup error output_message=$(kubectl auth can-i get pods 2>&1 "${kube_flags[@]}") kube::test::if_has_not_string "${output_message}" "Warning" # kubectl auth can-i get nodes prints a namespaced warning message output_message=$(kubectl auth can-i get nodes 2>&1 "${kube_flags[@]}") kube::test::if_has_string "${output_message}" "Warning: resource 'nodes' is not namespace scoped" # kubectl auth can-i get nodes --all-namespaces does not print a namespaced warning message output_message=$(kubectl auth can-i get nodes --all-namespaces 2>&1 "${kube_flags[@]}") kube::test::if_has_not_string "${output_message}" "Warning: resource 'nodes' is not namespace scoped" </ins> fi # kubectl auth reconcile