mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-04-15 07:16:34 +00:00
91 lines
2.3 KiB
Go
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
|
|
}
|