'kubectl auth can-i` command would not hint user when they try to access

some resource out of scope. For example, try get namespace inside defaut namespace.
It would be reject by api-server but `kubectl auth can-i get namespace --namespace=default`
would give a `yes`. After this patch, a warning info would be given.
For more detail, please refer issue #75950
k3s-v1.15.3
WanLinghao 2019-04-02 17:26:30 +08:00
parent aa74064600
commit 7fbd71835e
3 changed files with 58 additions and 5 deletions

View File

@ -34,6 +34,7 @@ go_library(
"//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",
"//staging/src/k8s.io/client-go/discovery:go_default_library",
"//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",

View File

@ -33,6 +33,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/cli-runtime/pkg/genericclioptions"
discovery "k8s.io/client-go/discovery"
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"
@ -44,11 +45,12 @@ import (
// 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 {
AllNamespaces bool
Quiet bool
NoHeaders bool
Namespace string
AuthClient authorizationv1client.AuthorizationV1Interface
AllNamespaces bool
Quiet bool
NoHeaders bool
Namespace string
AuthClient authorizationv1client.AuthorizationV1Interface
DiscoveryClient discovery.DiscoveryInterface
Verb string
Resource schema.GroupVersionResource
@ -169,6 +171,7 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
return err
}
o.AuthClient = client.AuthorizationV1()
o.DiscoveryClient = client.Discovery()
o.Namespace = ""
if !o.AllNamespaces {
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
@ -196,6 +199,14 @@ func (o *CanIOptions) Validate() error {
if o.Resource != (schema.GroupVersionResource{}) || o.ResourceName != "" {
return fmt.Errorf("NonResourceURL and ResourceName can not specified together")
}
} 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 scoped\n", 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)
}
}
}
if o.NoHeaders {
@ -360,3 +371,23 @@ func printAccess(out io.Writer, rules []rbacv1.PolicyRule) error {
}
return nil
}
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)
}

View File

@ -761,6 +761,27 @@ runTests() {
output_message=$(kubectl auth can-i get pods --subresource=log --quiet 2>&1 "${kube_flags[@]}"; echo $?)
kube::test::if_has_string "${output_message}" '0'
# 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"
fi
# kubectl auth reconcile