Files
troubleshoot/pkg/collect/rbac.go
Diamon Wiggins c7b84ad1e5 Refactor in-clusters collectors to use struct per collector (#670)
refactor in-clusters collectors to use struct per collector
2022-10-03 13:53:05 -04:00

91 lines
2.3 KiB
Go

package collect
import (
"context"
"fmt"
"github.com/pkg/errors"
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
authorizationv1 "k8s.io/api/authorization/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
type RBACErrors []error
func (e RBACErrors) GetRBACErrors() []error {
return e
}
func (e RBACErrors) HasRBACErrors() bool {
return len(e) > 0
}
func (e *RBACErrors) CheckRBAC(ctx context.Context, c Collector, collector *troubleshootv1beta2.Collect, clientConfig *rest.Config, namespace string) error {
exclude, err := c.IsExcluded()
if err != nil || exclude {
return nil
}
rbacErrors, err := checkRBAC(ctx, clientConfig, namespace, c.Title(), collector)
if err != nil {
return err
}
*e = rbacErrors
return nil
}
type RBACError struct {
DisplayName string
Namespace string
Resource string
Verb string
}
func (e RBACError) Error() string {
if e.Namespace == "" {
return fmt.Sprintf("cannot collect %s: action %q is not allowed on resource %q at the cluster scope", e.DisplayName, e.Verb, e.Resource)
}
return fmt.Sprintf("cannot collect %s: action %q is not allowed on resource %q in the %q namespace", e.DisplayName, e.Verb, e.Resource, e.Namespace)
}
func IsRBACError(err error) bool {
_, ok := errors.Cause(err).(RBACError)
return ok
}
func checkRBAC(ctx context.Context, clientConfig *rest.Config, namespace string, title string, collector *troubleshootv1beta2.Collect) ([]error, error) {
client, err := kubernetes.NewForConfig(clientConfig)
if err != nil {
return nil, errors.Wrap(err, "failed to create client from config")
}
forbidden := make([]error, 0)
specs := collector.AccessReviewSpecs(namespace)
for _, spec := range specs {
sar := &authorizationv1.SelfSubjectAccessReview{
Spec: spec,
}
resp, err := client.AuthorizationV1().SelfSubjectAccessReviews().Create(ctx, sar, metav1.CreateOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed to run subject review")
}
if !resp.Status.Allowed { // all other fields of Status are empty...
forbidden = append(forbidden, RBACError{
DisplayName: title,
Namespace: spec.ResourceAttributes.Namespace,
Resource: spec.ResourceAttributes.Resource,
Verb: spec.ResourceAttributes.Verb,
})
}
}
return forbidden, nil
}