2019-11-08 18:57:27 -08:00
|
|
|
package engine
|
|
|
|
|
|
|
|
import (
|
2023-02-01 14:38:04 +08:00
|
|
|
"fmt"
|
2023-01-31 16:28:48 +01:00
|
|
|
|
2022-05-17 13:12:43 +02:00
|
|
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
|
|
|
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
2023-03-22 11:18:11 +01:00
|
|
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
2022-12-02 09:14:23 +01:00
|
|
|
"github.com/kyverno/kyverno/pkg/config"
|
2023-01-31 16:28:48 +01:00
|
|
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
2022-12-02 09:14:23 +01:00
|
|
|
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
|
2023-01-03 10:33:09 +01:00
|
|
|
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
|
2022-12-02 09:14:23 +01:00
|
|
|
admissionv1 "k8s.io/api/admission/v1"
|
2022-12-09 22:15:23 +05:30
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2019-11-08 18:57:27 -08:00
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
2023-03-22 11:18:11 +01:00
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
2019-11-08 18:57:27 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
// PolicyContext contains the contexts for engine to process
|
|
|
|
type PolicyContext struct {
|
2022-12-02 09:14:23 +01:00
|
|
|
// policy is the policy to be processed
|
|
|
|
policy kyvernov1.PolicyInterface
|
2020-12-16 12:29:16 -08:00
|
|
|
|
2022-12-02 09:14:23 +01:00
|
|
|
// newResource is the resource to be processed
|
|
|
|
newResource unstructured.Unstructured
|
2020-12-16 12:29:16 -08:00
|
|
|
|
2022-12-02 09:14:23 +01:00
|
|
|
// oldResource is the prior resource for an update, or nil
|
|
|
|
oldResource unstructured.Unstructured
|
2020-12-16 12:29:16 -08:00
|
|
|
|
2022-12-02 09:14:23 +01:00
|
|
|
// element is set when the context is used for processing a foreach loop
|
|
|
|
element unstructured.Unstructured
|
2021-10-02 16:53:02 -07:00
|
|
|
|
2022-12-02 09:14:23 +01:00
|
|
|
// admissionInfo contains the admission request information
|
|
|
|
admissionInfo kyvernov1beta1.RequestInfo
|
2020-12-16 12:29:16 -08:00
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
// requestResource is GVR of the admission request
|
2022-12-09 22:15:23 +05:30
|
|
|
requestResource metav1.GroupVersionResource
|
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
// gvk is GVK of the top level resource
|
|
|
|
gvk schema.GroupVersionKind
|
|
|
|
|
|
|
|
// subresource is the subresource being requested, if any (for example, "status" or "scale")
|
|
|
|
subresource string
|
|
|
|
|
2022-12-02 09:14:23 +01:00
|
|
|
// jsonContext is the variable context
|
2022-12-12 07:20:20 -08:00
|
|
|
jsonContext enginectx.Interface
|
2022-12-02 09:14:23 +01:00
|
|
|
|
|
|
|
// namespaceLabels stores the label of namespace to be processed by namespace selector
|
|
|
|
namespaceLabels map[string]string
|
|
|
|
|
|
|
|
// admissionOperation represents if the caller is from the webhook server
|
|
|
|
admissionOperation bool
|
|
|
|
}
|
|
|
|
|
2023-01-31 16:28:48 +01:00
|
|
|
// engineapi.PolicyContext interface
|
2022-12-02 09:14:23 +01:00
|
|
|
|
|
|
|
func (c *PolicyContext) Policy() kyvernov1.PolicyInterface {
|
|
|
|
return c.policy
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) NewResource() unstructured.Unstructured {
|
|
|
|
return c.newResource
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) OldResource() unstructured.Unstructured {
|
|
|
|
return c.oldResource
|
|
|
|
}
|
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
func (c *PolicyContext) RequestResource() metav1.GroupVersionResource {
|
|
|
|
return c.requestResource
|
2022-12-02 09:14:23 +01:00
|
|
|
}
|
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
func (c *PolicyContext) ResourceKind() (schema.GroupVersionKind, string) {
|
|
|
|
// TODO: fallback
|
|
|
|
if c.gvk.Empty() {
|
|
|
|
return c.newResource.GroupVersionKind(), ""
|
|
|
|
}
|
|
|
|
return c.gvk, c.subresource
|
2023-01-31 16:28:48 +01:00
|
|
|
}
|
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
func (c *PolicyContext) AdmissionInfo() kyvernov1beta1.RequestInfo {
|
|
|
|
return c.admissionInfo
|
2023-01-31 16:28:48 +01:00
|
|
|
}
|
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
func (c *PolicyContext) NamespaceLabels() map[string]string {
|
|
|
|
return c.namespaceLabels
|
2023-01-31 16:28:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) AdmissionOperation() bool {
|
|
|
|
return c.admissionOperation
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) Element() unstructured.Unstructured {
|
|
|
|
return c.element
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) SetElement(element unstructured.Unstructured) {
|
|
|
|
c.element = element
|
|
|
|
}
|
|
|
|
|
2022-12-12 07:20:20 -08:00
|
|
|
func (c *PolicyContext) JSONContext() enginectx.Interface {
|
2022-12-02 09:14:23 +01:00
|
|
|
return c.jsonContext
|
|
|
|
}
|
|
|
|
|
2023-01-31 16:28:48 +01:00
|
|
|
func (c PolicyContext) Copy() engineapi.PolicyContext {
|
|
|
|
return c.copy()
|
|
|
|
}
|
|
|
|
|
2022-12-02 09:14:23 +01:00
|
|
|
// Mutators
|
|
|
|
|
|
|
|
func (c *PolicyContext) WithPolicy(policy kyvernov1.PolicyInterface) *PolicyContext {
|
2023-01-31 16:28:48 +01:00
|
|
|
copy := c.copy()
|
2022-12-02 09:14:23 +01:00
|
|
|
copy.policy = policy
|
|
|
|
return copy
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) WithNamespaceLabels(namespaceLabels map[string]string) *PolicyContext {
|
2023-01-31 16:28:48 +01:00
|
|
|
copy := c.copy()
|
2022-12-02 09:14:23 +01:00
|
|
|
copy.namespaceLabels = namespaceLabels
|
|
|
|
return copy
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) WithAdmissionInfo(admissionInfo kyvernov1beta1.RequestInfo) *PolicyContext {
|
2023-01-31 16:28:48 +01:00
|
|
|
copy := c.copy()
|
2022-12-02 09:14:23 +01:00
|
|
|
copy.admissionInfo = admissionInfo
|
|
|
|
return copy
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) WithNewResource(resource unstructured.Unstructured) *PolicyContext {
|
2023-01-31 16:28:48 +01:00
|
|
|
copy := c.copy()
|
2022-12-02 09:14:23 +01:00
|
|
|
copy.newResource = resource
|
|
|
|
return copy
|
|
|
|
}
|
2020-09-23 02:41:49 +05:30
|
|
|
|
2022-12-02 09:14:23 +01:00
|
|
|
func (c *PolicyContext) WithOldResource(resource unstructured.Unstructured) *PolicyContext {
|
2023-01-31 16:28:48 +01:00
|
|
|
copy := c.copy()
|
2022-12-02 09:14:23 +01:00
|
|
|
copy.oldResource = resource
|
|
|
|
return copy
|
|
|
|
}
|
2020-12-16 12:29:16 -08:00
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
func (c *PolicyContext) WithResourceKind(gvk schema.GroupVersionKind, subresource string) *PolicyContext {
|
2023-01-31 16:28:48 +01:00
|
|
|
copy := c.copy()
|
2023-03-22 11:18:11 +01:00
|
|
|
copy.gvk = gvk
|
|
|
|
copy.subresource = subresource
|
2022-12-02 09:14:23 +01:00
|
|
|
return copy
|
|
|
|
}
|
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
func (c *PolicyContext) WithRequestResource(gvr metav1.GroupVersionResource) *PolicyContext {
|
2023-01-31 16:28:48 +01:00
|
|
|
copy := c.copy()
|
2023-03-22 11:18:11 +01:00
|
|
|
copy.requestResource = gvr
|
2022-12-09 22:15:23 +05:30
|
|
|
return copy
|
|
|
|
}
|
|
|
|
|
2023-03-22 11:18:11 +01:00
|
|
|
func (c *PolicyContext) WithResources(newResource unstructured.Unstructured, oldResource unstructured.Unstructured) *PolicyContext {
|
|
|
|
return c.WithNewResource(newResource).WithOldResource(oldResource)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *PolicyContext) withAdmissionOperation(admissionOperation bool) *PolicyContext {
|
2023-01-31 16:28:48 +01:00
|
|
|
copy := c.copy()
|
2023-03-22 11:18:11 +01:00
|
|
|
copy.admissionOperation = admissionOperation
|
2022-12-09 22:15:23 +05:30
|
|
|
return copy
|
|
|
|
}
|
|
|
|
|
2023-01-31 16:28:48 +01:00
|
|
|
func (c PolicyContext) copy() *PolicyContext {
|
|
|
|
return &c
|
|
|
|
}
|
|
|
|
|
2022-12-16 04:13:14 -05:00
|
|
|
// Constructors
|
2023-02-06 06:49:47 +01:00
|
|
|
|
2022-12-12 07:20:20 -08:00
|
|
|
func NewPolicyContextWithJsonContext(jsonContext enginectx.Interface) *PolicyContext {
|
2021-09-27 14:28:55 -07:00
|
|
|
return &PolicyContext{
|
2023-02-06 06:49:47 +01:00
|
|
|
jsonContext: jsonContext,
|
2022-12-02 09:14:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewPolicyContext() *PolicyContext {
|
2022-12-12 07:20:20 -08:00
|
|
|
return NewPolicyContextWithJsonContext(enginectx.NewContext())
|
2022-12-02 09:14:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewPolicyContextFromAdmissionRequest(
|
2023-03-22 11:18:11 +01:00
|
|
|
client dclient.IDiscovery,
|
2022-12-02 09:14:23 +01:00
|
|
|
request *admissionv1.AdmissionRequest,
|
|
|
|
admissionInfo kyvernov1beta1.RequestInfo,
|
|
|
|
configuration config.Configuration,
|
|
|
|
) (*PolicyContext, error) {
|
|
|
|
ctx, err := newVariablesContext(request, &admissionInfo)
|
|
|
|
if err != nil {
|
2023-02-01 14:38:04 +08:00
|
|
|
return nil, fmt.Errorf("failed to create policy rule context: %w", err)
|
2022-12-02 09:14:23 +01:00
|
|
|
}
|
2023-01-03 10:33:09 +01:00
|
|
|
newResource, oldResource, err := admissionutils.ExtractResources(nil, request)
|
2022-12-02 09:14:23 +01:00
|
|
|
if err != nil {
|
2023-02-01 14:38:04 +08:00
|
|
|
return nil, fmt.Errorf("failed to parse resource: %w", err)
|
2022-12-02 09:14:23 +01:00
|
|
|
}
|
2023-01-02 18:14:40 +01:00
|
|
|
if err := ctx.AddImageInfos(&newResource, configuration); err != nil {
|
2023-02-01 14:38:04 +08:00
|
|
|
return nil, fmt.Errorf("failed to add image information to the policy rule context: %w", err)
|
2022-12-02 09:14:23 +01:00
|
|
|
}
|
2023-03-22 11:18:11 +01:00
|
|
|
gvk, err := client.GetGVKFromGVR(schema.GroupVersionResource(request.Resource))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-12-02 09:14:23 +01:00
|
|
|
policyContext := NewPolicyContextWithJsonContext(ctx).
|
|
|
|
WithNewResource(newResource).
|
|
|
|
WithOldResource(oldResource).
|
|
|
|
WithAdmissionInfo(admissionInfo).
|
2023-02-06 06:49:47 +01:00
|
|
|
withAdmissionOperation(true).
|
2023-03-22 11:18:11 +01:00
|
|
|
WithResourceKind(gvk, request.SubResource).
|
|
|
|
WithRequestResource(request.Resource)
|
2022-12-02 09:14:23 +01:00
|
|
|
return policyContext, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func newVariablesContext(request *admissionv1.AdmissionRequest, userRequestInfo *kyvernov1beta1.RequestInfo) (enginectx.Interface, error) {
|
|
|
|
ctx := enginectx.NewContext()
|
|
|
|
if err := ctx.AddRequest(request); err != nil {
|
2023-02-01 14:38:04 +08:00
|
|
|
return nil, fmt.Errorf("failed to load incoming request in context: %w", err)
|
2022-12-02 09:14:23 +01:00
|
|
|
}
|
|
|
|
if err := ctx.AddUserInfo(*userRequestInfo); err != nil {
|
2023-02-01 14:38:04 +08:00
|
|
|
return nil, fmt.Errorf("failed to load userInfo in context: %w", err)
|
2022-12-02 09:14:23 +01:00
|
|
|
}
|
|
|
|
if err := ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username); err != nil {
|
2023-02-01 14:38:04 +08:00
|
|
|
return nil, fmt.Errorf("failed to load service account in context: %w", err)
|
2021-09-27 14:28:55 -07:00
|
|
|
}
|
2022-12-02 09:14:23 +01:00
|
|
|
return ctx, nil
|
2021-09-27 23:40:05 -07:00
|
|
|
}
|