Skip to content

Commit

Permalink
Merge pull request kubernetes#76014 from WanLinghao/auth_can-i_improve
Browse files Browse the repository at this point in the history
Improve `kubectl auth can-i` command by warning users when they try access resource out of scope
  • Loading branch information
k8s-ci-robot authored Apr 16, 2019
2 parents 701e36b + 7fbd718 commit 4c4c378
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 5 deletions.
1 change: 1 addition & 0 deletions pkg/kubectl/cmd/auth/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
41 changes: 36 additions & 5 deletions pkg/kubectl/cmd/auth/cani.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
21 changes: 21 additions & 0 deletions test/cmd/legacy-script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 4c4c378

Please sign in to comment.