1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-15 17:51:20 +00:00
kyverno/pkg/auth/auth.go
Charles-Edouard Brétéché aadaec09e1
fix: remove a couple DeepEqual and fix deletion check bug (#6640)
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
2023-03-22 04:46:35 +00:00

108 lines
3.6 KiB
Go

package auth
import (
"context"
"fmt"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
authorizationv1 "k8s.io/api/authorization/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
authorizationv1client "k8s.io/client-go/kubernetes/typed/authorization/v1"
)
// Discovery provides interface to mange Kind and GVR mapping
type Discovery interface {
GetGVRFromGVK(schema.GroupVersionKind) (schema.GroupVersionResource, error)
}
// CanIOptions provides utility to check if user has authorization for the given operation
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
// - each can generates a SelfSubjectAccessReview resource and response is evaluated for permissions
RunAccessCheck(context.Context) (bool, error)
}
type canIOptions struct {
namespace string
verb string
kind string
subresource string
discovery Discovery
ssarClient authorizationv1client.SelfSubjectAccessReviewInterface
}
// NewCanI returns a new instance of operation access controller evaluator
func NewCanI(discovery Discovery, ssarClient authorizationv1client.SelfSubjectAccessReviewInterface, kind, namespace, verb, subresource string) CanIOptions {
return &canIOptions{
namespace: namespace,
verb: verb,
kind: kind,
subresource: subresource,
discovery: discovery,
ssarClient: ssarClient,
}
}
// 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
// - each can generates a SelfSubjectAccessReview resource and response is evaluated for permissions
func (o *canIOptions) RunAccessCheck(ctx context.Context) (bool, error) {
// get GroupVersionResource from RESTMapper
// get GVR from kind
apiVersion, kind := kubeutils.GetKindFromGVK(o.kind)
gv, err := schema.ParseGroupVersion(apiVersion)
if err != nil {
return false, fmt.Errorf("failed to parse group/version %s", apiVersion)
}
gvr, err := o.discovery.GetGVRFromGVK(gv.WithKind(kind))
if err != nil {
return false, fmt.Errorf("failed to get GVR for kind %s", o.kind)
}
if gvr.Empty() {
// cannot find GVR
return false, fmt.Errorf("failed to get the Group Version Resource for kind %s", o.kind)
}
sar := &authorizationv1.SelfSubjectAccessReview{
Spec: authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: o.namespace,
Verb: o.verb,
Group: gvr.Group,
Resource: gvr.Resource,
Subresource: o.subresource,
},
},
}
// Set self subject access review
// - namespace
// - verb
// - resource
// - subresource
logger := logger.WithValues("kind", sar.Kind, "namespace", sar.Namespace, "name", sar.Name)
// Create the Resource
resp, err := o.ssarClient.Create(ctx, sar, metav1.CreateOptions{})
if err != nil {
logger.Error(err, "failed to create resource")
return false, err
}
if !resp.Status.Allowed {
reason := resp.Status.Reason
evaluationError := resp.Status.EvaluationError
// Reporting ? (just logs)
logger.Info("disallowed operation", "reason", reason, "evaluationError", evaluationError)
}
return resp.Status.Allowed, nil
}