mirror of https://github.com/k3s-io/k3s
'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 #75950k3s-v1.15.3
parent
aa74064600
commit
7fbd71835e
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue