2020-03-12 01:14:23 +00:00
|
|
|
package auth
|
|
|
|
|
|
|
|
import (
|
2022-11-29 13:59:40 +00:00
|
|
|
"context"
|
2020-03-12 01:14:23 +00:00
|
|
|
"fmt"
|
|
|
|
|
2023-05-30 10:01:44 +00:00
|
|
|
"github.com/kyverno/kyverno/pkg/auth/checker"
|
2023-03-10 07:15:48 +00:00
|
|
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
2020-03-12 01:14:23 +00:00
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
2022-12-22 05:24:37 +00:00
|
|
|
authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
|
2020-03-12 01:14:23 +00:00
|
|
|
)
|
|
|
|
|
2022-12-22 05:24:37 +00:00
|
|
|
// Discovery provides interface to mange Kind and GVR mapping
|
|
|
|
type Discovery interface {
|
2023-03-10 07:15:48 +00:00
|
|
|
GetGVRFromGVK(schema.GroupVersionKind) (schema.GroupVersionResource, error)
|
2022-12-22 05:24:37 +00:00
|
|
|
}
|
|
|
|
|
2022-05-17 06:19:03 +00:00
|
|
|
// CanIOptions provides utility to check if user has authorization for the given operation
|
2022-09-07 06:54:34 +00:00
|
|
|
type CanIOptions interface {
|
|
|
|
// RunAccessCheck checks if the caller can perform the operation
|
|
|
|
// - operation is a combination of namespace, kind, verb
|
|
|
|
// - can only evaluate a single verb
|
|
|
|
// - group version resource is determined from the kind using the discovery client REST mapper
|
|
|
|
// - If disallowed, the reason and evaluationError is available in the logs
|
2023-04-24 10:31:42 +00:00
|
|
|
// - each can generates a SubjectAccessReview resource and response is evaluated for permissions
|
2023-09-05 10:16:50 +00:00
|
|
|
RunAccessCheck(context.Context) (bool, string, error)
|
2022-09-07 06:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type canIOptions struct {
|
2022-12-21 17:12:26 +00:00
|
|
|
namespace string
|
|
|
|
verb string
|
2023-06-22 14:14:06 +00:00
|
|
|
gvk string
|
2022-12-21 17:12:26 +00:00
|
|
|
subresource string
|
2023-04-24 10:31:42 +00:00
|
|
|
user string
|
2024-08-07 12:46:44 +00:00
|
|
|
name string
|
2022-12-22 05:24:37 +00:00
|
|
|
discovery Discovery
|
2023-05-30 10:01:44 +00:00
|
|
|
checker checker.AuthChecker
|
2020-03-12 01:14:23 +00:00
|
|
|
}
|
|
|
|
|
2022-05-17 06:19:03 +00:00
|
|
|
// NewCanI returns a new instance of operation access controller evaluator
|
2024-08-07 12:46:44 +00:00
|
|
|
func NewCanI(discovery Discovery, sarClient authorizationv1client.SubjectAccessReviewInterface, gvk, namespace, name, verb, subresource string, user string) CanIOptions {
|
2022-09-07 06:54:34 +00:00
|
|
|
return &canIOptions{
|
2024-08-07 12:46:44 +00:00
|
|
|
name: name,
|
2022-12-21 17:12:26 +00:00
|
|
|
namespace: namespace,
|
|
|
|
verb: verb,
|
2023-06-22 14:14:06 +00:00
|
|
|
gvk: gvk,
|
2022-12-21 17:12:26 +00:00
|
|
|
subresource: subresource,
|
2023-04-24 10:31:42 +00:00
|
|
|
user: user,
|
2022-12-22 05:24:37 +00:00
|
|
|
discovery: discovery,
|
2023-05-30 10:01:44 +00:00
|
|
|
checker: checker.NewSubjectChecker(sarClient, user, nil),
|
2020-03-12 01:14:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-17 06:19:03 +00:00
|
|
|
// RunAccessCheck checks if the caller can perform the operation
|
2020-03-12 01:14:23 +00:00
|
|
|
// - operation is a combination of namespace, kind, verb
|
|
|
|
// - can only evaluate a single verb
|
|
|
|
// - group version resource is determined from the kind using the discovery client REST mapper
|
2020-08-30 08:43:20 +00:00
|
|
|
// - If disallowed, the reason and evaluationError is available in the logs
|
2020-03-12 01:14:23 +00:00
|
|
|
// - each can generates a SelfSubjectAccessReview resource and response is evaluated for permissions
|
2023-09-05 10:16:50 +00:00
|
|
|
func (o *canIOptions) RunAccessCheck(ctx context.Context) (bool, string, error) {
|
2020-03-12 01:14:23 +00:00
|
|
|
// get GroupVersionResource from RESTMapper
|
|
|
|
// get GVR from kind
|
2023-06-22 14:14:06 +00:00
|
|
|
apiVersion, kind := kubeutils.GetKindFromGVK(o.gvk)
|
2023-03-10 07:15:48 +00:00
|
|
|
gv, err := schema.ParseGroupVersion(apiVersion)
|
|
|
|
if err != nil {
|
2023-09-05 10:16:50 +00:00
|
|
|
return false, "", fmt.Errorf("failed to parse group/version %s", apiVersion)
|
2023-03-10 07:15:48 +00:00
|
|
|
}
|
|
|
|
gvr, err := o.discovery.GetGVRFromGVK(gv.WithKind(kind))
|
2020-12-04 03:19:36 +00:00
|
|
|
if err != nil {
|
2023-09-05 10:16:50 +00:00
|
|
|
return false, "", fmt.Errorf("failed to get GVR for kind %s", o.gvk)
|
2020-12-04 03:19:36 +00:00
|
|
|
}
|
2023-03-22 04:46:35 +00:00
|
|
|
if gvr.Empty() {
|
2020-03-12 01:14:23 +00:00
|
|
|
// cannot find GVR
|
2023-09-05 10:16:50 +00:00
|
|
|
return false, "", fmt.Errorf("failed to get the Group Version Resource for kind %s", o.gvk)
|
2020-03-12 01:14:23 +00:00
|
|
|
}
|
2023-05-30 10:01:44 +00:00
|
|
|
logger := logger.WithValues("kind", kind, "namespace", o.namespace, "gvr", gvr.String(), "verb", o.verb)
|
2024-08-07 12:46:44 +00:00
|
|
|
result, err := o.checker.Check(ctx, gvr.Group, gvr.Version, gvr.Resource, o.subresource, o.namespace, o.name, o.verb)
|
2020-03-12 01:14:23 +00:00
|
|
|
if err != nil {
|
2023-05-30 10:01:44 +00:00
|
|
|
logger.Error(err, "failed to check permissions")
|
2023-09-05 10:16:50 +00:00
|
|
|
return false, "", err
|
2020-03-12 01:14:23 +00:00
|
|
|
}
|
2023-05-30 10:01:44 +00:00
|
|
|
if !result.Allowed {
|
|
|
|
logger.Info("disallowed operation", "reason", result.Reason, "evaluationError", result.EvaluationError)
|
2020-03-12 01:14:23 +00:00
|
|
|
}
|
2023-09-05 10:16:50 +00:00
|
|
|
return result.Allowed, result.Reason, nil
|
2020-03-12 01:14:23 +00:00
|
|
|
}
|