mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
feat: add context/preconditions support to mutate existing (#6754)
* refactor: engine handlers Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * feat: add context/preconditions support to mutate existing Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * kuttl Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * readme Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix and context kuttl test Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * validation Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * final fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
parent
16d57f0940
commit
40ac8eb863
47 changed files with 4326 additions and 306 deletions
|
@ -266,7 +266,7 @@ func (r ResourceFilter) IsEmpty() bool {
|
|||
type Mutation struct {
|
||||
// Targets defines the target resources to be mutated.
|
||||
// +optional
|
||||
Targets []ResourceSpec `json:"targets,omitempty" yaml:"targets,omitempty"`
|
||||
Targets []TargetResourceSpec `json:"targets,omitempty" yaml:"targets,omitempty"`
|
||||
|
||||
// PatchStrategicMerge is a strategic merge patch used to modify resources.
|
||||
// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package v1
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
)
|
||||
|
||||
type ResourceSpec struct {
|
||||
// APIVersion specifies resource apiVersion.
|
||||
|
@ -24,3 +29,25 @@ func (s ResourceSpec) GetAPIVersion() string { return s.APIVersion }
|
|||
func (s ResourceSpec) String() string {
|
||||
return strings.Join([]string{s.APIVersion, s.Kind, s.Namespace, s.Name}, "/")
|
||||
}
|
||||
|
||||
// TargetResourceSpec defines targets for mutating existing resources.
|
||||
type TargetResourceSpec struct {
|
||||
// ResourceSpec contains the target resources to load when mutating existing resources.
|
||||
ResourceSpec `json:",omitempty" yaml:",omitempty"`
|
||||
|
||||
// Context defines variables and data sources that can be used during rule execution.
|
||||
// +optional
|
||||
Context []ContextEntry `json:"context,omitempty" yaml:"context,omitempty"`
|
||||
|
||||
// Preconditions are used to determine if a policy rule should be applied by evaluating a
|
||||
// set of conditions. The declaration can contain nested `any` or `all` statements. A direct list
|
||||
// of conditions (without `any` or `all` statements is supported for backwards compatibility but
|
||||
// will be deprecated in the next major release.
|
||||
// See: https://kyverno.io/docs/writing-policies/preconditions/
|
||||
// +optional
|
||||
RawAnyAllConditions *apiextv1.JSON `json:"preconditions,omitempty" yaml:"preconditions,omitempty"`
|
||||
}
|
||||
|
||||
func (r *TargetResourceSpec) GetAnyAllConditions() apiextensions.JSON {
|
||||
return FromJSON(r.RawAnyAllConditions)
|
||||
}
|
||||
|
|
|
@ -775,8 +775,10 @@ func (in *Mutation) DeepCopyInto(out *Mutation) {
|
|||
*out = *in
|
||||
if in.Targets != nil {
|
||||
in, out := &in.Targets, &out.Targets
|
||||
*out = make([]ResourceSpec, len(*in))
|
||||
copy(*out, *in)
|
||||
*out = make([]TargetResourceSpec, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.RawPatchStrategicMerge != nil {
|
||||
in, out := &in.RawPatchStrategicMerge, &out.RawPatchStrategicMerge
|
||||
|
@ -1267,6 +1269,34 @@ func (in *StaticKeyAttestor) DeepCopy() *StaticKeyAttestor {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TargetResourceSpec) DeepCopyInto(out *TargetResourceSpec) {
|
||||
*out = *in
|
||||
out.ResourceSpec = in.ResourceSpec
|
||||
if in.Context != nil {
|
||||
in, out := &in.Context, &out.Context
|
||||
*out = make([]ContextEntry, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.RawAnyAllConditions != nil {
|
||||
in, out := &in.RawAnyAllConditions, &out.RawAnyAllConditions
|
||||
*out = new(apiextensionsv1.JSON)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetResourceSpec.
|
||||
func (in *TargetResourceSpec) DeepCopy() *TargetResourceSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TargetResourceSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UserInfo) DeepCopyInto(out *UserInfo) {
|
||||
*out = *in
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2060,10 +2060,147 @@ spec:
|
|||
description: Targets defines the target resources to be
|
||||
mutated.
|
||||
items:
|
||||
description: TargetResourceSpec defines targets for mutating
|
||||
existing resources.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
context:
|
||||
description: Context defines variables and data sources
|
||||
that can be used during rule execution.
|
||||
items:
|
||||
description: ContextEntry adds variables and data
|
||||
sources to a rule Context. Either a ConfigMap
|
||||
reference or a APILookup must be provided.
|
||||
properties:
|
||||
apiCall:
|
||||
description: APICall is an HTTP request to the
|
||||
Kubernetes API server, or other JSON web service.
|
||||
The data returned is stored in the context
|
||||
with the name for the context entry.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JSON
|
||||
Match Expression that can be used to transform
|
||||
the JSON response returned from the server.
|
||||
For example a JMESPath of "items | length(@)"
|
||||
applied to the API server response for
|
||||
the URLPath "/apis/apps/v1/deployments"
|
||||
will return the total count of deployments
|
||||
across all namespaces.
|
||||
type: string
|
||||
service:
|
||||
description: Service is an API call to a
|
||||
JSON web service
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is a PEM encoded
|
||||
CA bundle which will be used to validate
|
||||
the server certificate.
|
||||
type: string
|
||||
data:
|
||||
description: Data specifies the POST
|
||||
data sent to the server.
|
||||
items:
|
||||
description: RequestData contains
|
||||
the HTTP POST data
|
||||
properties:
|
||||
key:
|
||||
description: Key is a unique identifier
|
||||
for the data value
|
||||
type: string
|
||||
value:
|
||||
description: Value is the data
|
||||
value
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
requestType:
|
||||
default: GET
|
||||
description: Method is the HTTP request
|
||||
type (GET or POST).
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
type: string
|
||||
urlPath:
|
||||
description: URL is the JSON web service
|
||||
URL. The typical format is `https://{service}.{namespace}:{port}/{path}`.
|
||||
type: string
|
||||
required:
|
||||
- requestType
|
||||
- urlPath
|
||||
type: object
|
||||
urlPath:
|
||||
description: URLPath is the URL path to
|
||||
be used in the HTTP GET request to the
|
||||
Kubernetes API server (e.g. "/api/v1/namespaces"
|
||||
or "/apis/apps/v1/deployments"). The
|
||||
format required is the same format used
|
||||
by the `kubectl get --raw` command.
|
||||
type: string
|
||||
type: object
|
||||
configMap:
|
||||
description: ConfigMap is the ConfigMap reference.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the ConfigMap name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the ConfigMap
|
||||
namespace.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
imageRegistry:
|
||||
description: ImageRegistry defines requests
|
||||
to an OCI/Docker V2 registry to fetch image
|
||||
details.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JSON
|
||||
Match Expression that can be used to transform
|
||||
the ImageData struct returned as a result
|
||||
of processing the image reference.
|
||||
type: string
|
||||
reference:
|
||||
description: 'Reference is image reference
|
||||
to a container image in the registry.
|
||||
Example: ghcr.io/kyverno/kyverno:latest'
|
||||
type: string
|
||||
required:
|
||||
- reference
|
||||
type: object
|
||||
name:
|
||||
description: Name is the variable name.
|
||||
type: string
|
||||
variable:
|
||||
description: Variable defines an arbitrary JMESPath
|
||||
context variable that can be defined inline.
|
||||
properties:
|
||||
default:
|
||||
description: Default is an optional arbitrary
|
||||
JSON object that the variable may take
|
||||
if the JMESPath expression evaluates to
|
||||
nil
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JMESPath
|
||||
Expression that can be used to transform
|
||||
the variable.
|
||||
type: string
|
||||
value:
|
||||
description: Value is any arbitrary JSON
|
||||
object representable in YAML or JSON form.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
|
@ -2073,6 +2210,15 @@ spec:
|
|||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
preconditions:
|
||||
description: 'Preconditions are used to determine
|
||||
if a policy rule should be applied by evaluating
|
||||
a set of conditions. The declaration can contain
|
||||
nested `any` or `all` statements. A direct list
|
||||
of conditions (without `any` or `all` statements
|
||||
is supported for backwards compatibility but will
|
||||
be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/'
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
|
@ -5476,10 +5622,155 @@ spec:
|
|||
description: Targets defines the target resources to
|
||||
be mutated.
|
||||
items:
|
||||
description: TargetResourceSpec defines targets for
|
||||
mutating existing resources.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
context:
|
||||
description: Context defines variables and data
|
||||
sources that can be used during rule execution.
|
||||
items:
|
||||
description: ContextEntry adds variables and
|
||||
data sources to a rule Context. Either a ConfigMap
|
||||
reference or a APILookup must be provided.
|
||||
properties:
|
||||
apiCall:
|
||||
description: APICall is an HTTP request
|
||||
to the Kubernetes API server, or other
|
||||
JSON web service. The data returned is
|
||||
stored in the context with the name for
|
||||
the context entry.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JSON Match Expression that can be
|
||||
used to transform the JSON response
|
||||
returned from the server. For example
|
||||
a JMESPath of "items | length(@)"
|
||||
applied to the API server response
|
||||
for the URLPath "/apis/apps/v1/deployments"
|
||||
will return the total count of deployments
|
||||
across all namespaces.
|
||||
type: string
|
||||
service:
|
||||
description: Service is an API call
|
||||
to a JSON web service
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is a PEM encoded
|
||||
CA bundle which will be used to
|
||||
validate the server certificate.
|
||||
type: string
|
||||
data:
|
||||
description: Data specifies the
|
||||
POST data sent to the server.
|
||||
items:
|
||||
description: RequestData contains
|
||||
the HTTP POST data
|
||||
properties:
|
||||
key:
|
||||
description: Key is a unique
|
||||
identifier for the data
|
||||
value
|
||||
type: string
|
||||
value:
|
||||
description: Value is the
|
||||
data value
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
requestType:
|
||||
default: GET
|
||||
description: Method is the HTTP
|
||||
request type (GET or POST).
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
type: string
|
||||
urlPath:
|
||||
description: URL is the JSON web
|
||||
service URL. The typical format
|
||||
is `https://{service}.{namespace}:{port}/{path}`.
|
||||
type: string
|
||||
required:
|
||||
- requestType
|
||||
- urlPath
|
||||
type: object
|
||||
urlPath:
|
||||
description: URLPath is the URL path
|
||||
to be used in the HTTP GET request
|
||||
to the Kubernetes API server (e.g.
|
||||
"/api/v1/namespaces" or "/apis/apps/v1/deployments").
|
||||
The format required is the same format
|
||||
used by the `kubectl get --raw` command.
|
||||
type: string
|
||||
type: object
|
||||
configMap:
|
||||
description: ConfigMap is the ConfigMap
|
||||
reference.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the ConfigMap name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the ConfigMap
|
||||
namespace.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
imageRegistry:
|
||||
description: ImageRegistry defines requests
|
||||
to an OCI/Docker V2 registry to fetch
|
||||
image details.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JSON Match Expression that can be
|
||||
used to transform the ImageData struct
|
||||
returned as a result of processing
|
||||
the image reference.
|
||||
type: string
|
||||
reference:
|
||||
description: 'Reference is image reference
|
||||
to a container image in the registry.
|
||||
Example: ghcr.io/kyverno/kyverno:latest'
|
||||
type: string
|
||||
required:
|
||||
- reference
|
||||
type: object
|
||||
name:
|
||||
description: Name is the variable name.
|
||||
type: string
|
||||
variable:
|
||||
description: Variable defines an arbitrary
|
||||
JMESPath context variable that can be
|
||||
defined inline.
|
||||
properties:
|
||||
default:
|
||||
description: Default is an optional
|
||||
arbitrary JSON object that the variable
|
||||
may take if the JMESPath expression
|
||||
evaluates to nil
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JMESPath Expression that can be used
|
||||
to transform the variable.
|
||||
type: string
|
||||
value:
|
||||
description: Value is any arbitrary
|
||||
JSON object representable in YAML
|
||||
or JSON form.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
|
@ -5489,6 +5780,16 @@ spec:
|
|||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
preconditions:
|
||||
description: 'Preconditions are used to determine
|
||||
if a policy rule should be applied by evaluating
|
||||
a set of conditions. The declaration can contain
|
||||
nested `any` or `all` statements. A direct list
|
||||
of conditions (without `any` or `all` statements
|
||||
is supported for backwards compatibility but
|
||||
will be deprecated in the next major release.
|
||||
See: https://kyverno.io/docs/writing-policies/preconditions/'
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
|
@ -8536,10 +8837,147 @@ spec:
|
|||
description: Targets defines the target resources to be
|
||||
mutated.
|
||||
items:
|
||||
description: TargetResourceSpec defines targets for mutating
|
||||
existing resources.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
context:
|
||||
description: Context defines variables and data sources
|
||||
that can be used during rule execution.
|
||||
items:
|
||||
description: ContextEntry adds variables and data
|
||||
sources to a rule Context. Either a ConfigMap
|
||||
reference or a APILookup must be provided.
|
||||
properties:
|
||||
apiCall:
|
||||
description: APICall is an HTTP request to the
|
||||
Kubernetes API server, or other JSON web service.
|
||||
The data returned is stored in the context
|
||||
with the name for the context entry.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JSON
|
||||
Match Expression that can be used to transform
|
||||
the JSON response returned from the server.
|
||||
For example a JMESPath of "items | length(@)"
|
||||
applied to the API server response for
|
||||
the URLPath "/apis/apps/v1/deployments"
|
||||
will return the total count of deployments
|
||||
across all namespaces.
|
||||
type: string
|
||||
service:
|
||||
description: Service is an API call to a
|
||||
JSON web service
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is a PEM encoded
|
||||
CA bundle which will be used to validate
|
||||
the server certificate.
|
||||
type: string
|
||||
data:
|
||||
description: Data specifies the POST
|
||||
data sent to the server.
|
||||
items:
|
||||
description: RequestData contains
|
||||
the HTTP POST data
|
||||
properties:
|
||||
key:
|
||||
description: Key is a unique identifier
|
||||
for the data value
|
||||
type: string
|
||||
value:
|
||||
description: Value is the data
|
||||
value
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
requestType:
|
||||
default: GET
|
||||
description: Method is the HTTP request
|
||||
type (GET or POST).
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
type: string
|
||||
urlPath:
|
||||
description: URL is the JSON web service
|
||||
URL. The typical format is `https://{service}.{namespace}:{port}/{path}`.
|
||||
type: string
|
||||
required:
|
||||
- requestType
|
||||
- urlPath
|
||||
type: object
|
||||
urlPath:
|
||||
description: URLPath is the URL path to
|
||||
be used in the HTTP GET request to the
|
||||
Kubernetes API server (e.g. "/api/v1/namespaces"
|
||||
or "/apis/apps/v1/deployments"). The
|
||||
format required is the same format used
|
||||
by the `kubectl get --raw` command.
|
||||
type: string
|
||||
type: object
|
||||
configMap:
|
||||
description: ConfigMap is the ConfigMap reference.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the ConfigMap name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the ConfigMap
|
||||
namespace.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
imageRegistry:
|
||||
description: ImageRegistry defines requests
|
||||
to an OCI/Docker V2 registry to fetch image
|
||||
details.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JSON
|
||||
Match Expression that can be used to transform
|
||||
the ImageData struct returned as a result
|
||||
of processing the image reference.
|
||||
type: string
|
||||
reference:
|
||||
description: 'Reference is image reference
|
||||
to a container image in the registry.
|
||||
Example: ghcr.io/kyverno/kyverno:latest'
|
||||
type: string
|
||||
required:
|
||||
- reference
|
||||
type: object
|
||||
name:
|
||||
description: Name is the variable name.
|
||||
type: string
|
||||
variable:
|
||||
description: Variable defines an arbitrary JMESPath
|
||||
context variable that can be defined inline.
|
||||
properties:
|
||||
default:
|
||||
description: Default is an optional arbitrary
|
||||
JSON object that the variable may take
|
||||
if the JMESPath expression evaluates to
|
||||
nil
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JMESPath
|
||||
Expression that can be used to transform
|
||||
the variable.
|
||||
type: string
|
||||
value:
|
||||
description: Value is any arbitrary JSON
|
||||
object representable in YAML or JSON form.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
|
@ -8549,6 +8987,15 @@ spec:
|
|||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
preconditions:
|
||||
description: 'Preconditions are used to determine
|
||||
if a policy rule should be applied by evaluating
|
||||
a set of conditions. The declaration can contain
|
||||
nested `any` or `all` statements. A direct list
|
||||
of conditions (without `any` or `all` statements
|
||||
is supported for backwards compatibility but will
|
||||
be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/'
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
|
@ -12080,10 +12527,155 @@ spec:
|
|||
description: Targets defines the target resources to
|
||||
be mutated.
|
||||
items:
|
||||
description: TargetResourceSpec defines targets for
|
||||
mutating existing resources.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
context:
|
||||
description: Context defines variables and data
|
||||
sources that can be used during rule execution.
|
||||
items:
|
||||
description: ContextEntry adds variables and
|
||||
data sources to a rule Context. Either a ConfigMap
|
||||
reference or a APILookup must be provided.
|
||||
properties:
|
||||
apiCall:
|
||||
description: APICall is an HTTP request
|
||||
to the Kubernetes API server, or other
|
||||
JSON web service. The data returned is
|
||||
stored in the context with the name for
|
||||
the context entry.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JSON Match Expression that can be
|
||||
used to transform the JSON response
|
||||
returned from the server. For example
|
||||
a JMESPath of "items | length(@)"
|
||||
applied to the API server response
|
||||
for the URLPath "/apis/apps/v1/deployments"
|
||||
will return the total count of deployments
|
||||
across all namespaces.
|
||||
type: string
|
||||
service:
|
||||
description: Service is an API call
|
||||
to a JSON web service
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is a PEM encoded
|
||||
CA bundle which will be used to
|
||||
validate the server certificate.
|
||||
type: string
|
||||
data:
|
||||
description: Data specifies the
|
||||
POST data sent to the server.
|
||||
items:
|
||||
description: RequestData contains
|
||||
the HTTP POST data
|
||||
properties:
|
||||
key:
|
||||
description: Key is a unique
|
||||
identifier for the data
|
||||
value
|
||||
type: string
|
||||
value:
|
||||
description: Value is the
|
||||
data value
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
requestType:
|
||||
default: GET
|
||||
description: Method is the HTTP
|
||||
request type (GET or POST).
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
type: string
|
||||
urlPath:
|
||||
description: URL is the JSON web
|
||||
service URL. The typical format
|
||||
is `https://{service}.{namespace}:{port}/{path}`.
|
||||
type: string
|
||||
required:
|
||||
- requestType
|
||||
- urlPath
|
||||
type: object
|
||||
urlPath:
|
||||
description: URLPath is the URL path
|
||||
to be used in the HTTP GET request
|
||||
to the Kubernetes API server (e.g.
|
||||
"/api/v1/namespaces" or "/apis/apps/v1/deployments").
|
||||
The format required is the same format
|
||||
used by the `kubectl get --raw` command.
|
||||
type: string
|
||||
type: object
|
||||
configMap:
|
||||
description: ConfigMap is the ConfigMap
|
||||
reference.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the ConfigMap name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the ConfigMap
|
||||
namespace.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
imageRegistry:
|
||||
description: ImageRegistry defines requests
|
||||
to an OCI/Docker V2 registry to fetch
|
||||
image details.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JSON Match Expression that can be
|
||||
used to transform the ImageData struct
|
||||
returned as a result of processing
|
||||
the image reference.
|
||||
type: string
|
||||
reference:
|
||||
description: 'Reference is image reference
|
||||
to a container image in the registry.
|
||||
Example: ghcr.io/kyverno/kyverno:latest'
|
||||
type: string
|
||||
required:
|
||||
- reference
|
||||
type: object
|
||||
name:
|
||||
description: Name is the variable name.
|
||||
type: string
|
||||
variable:
|
||||
description: Variable defines an arbitrary
|
||||
JMESPath context variable that can be
|
||||
defined inline.
|
||||
properties:
|
||||
default:
|
||||
description: Default is an optional
|
||||
arbitrary JSON object that the variable
|
||||
may take if the JMESPath expression
|
||||
evaluates to nil
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JMESPath Expression that can be used
|
||||
to transform the variable.
|
||||
type: string
|
||||
value:
|
||||
description: Value is any arbitrary
|
||||
JSON object representable in YAML
|
||||
or JSON form.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
|
@ -12093,6 +12685,16 @@ spec:
|
|||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
preconditions:
|
||||
description: 'Preconditions are used to determine
|
||||
if a policy rule should be applied by evaluating
|
||||
a set of conditions. The declaration can contain
|
||||
nested `any` or `all` statements. A direct list
|
||||
of conditions (without `any` or `all` statements
|
||||
is supported for backwards compatibility but
|
||||
will be deprecated in the next major release.
|
||||
See: https://kyverno.io/docs/writing-policies/preconditions/'
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
|
|
|
@ -2061,10 +2061,147 @@ spec:
|
|||
description: Targets defines the target resources to be
|
||||
mutated.
|
||||
items:
|
||||
description: TargetResourceSpec defines targets for mutating
|
||||
existing resources.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
context:
|
||||
description: Context defines variables and data sources
|
||||
that can be used during rule execution.
|
||||
items:
|
||||
description: ContextEntry adds variables and data
|
||||
sources to a rule Context. Either a ConfigMap
|
||||
reference or a APILookup must be provided.
|
||||
properties:
|
||||
apiCall:
|
||||
description: APICall is an HTTP request to the
|
||||
Kubernetes API server, or other JSON web service.
|
||||
The data returned is stored in the context
|
||||
with the name for the context entry.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JSON
|
||||
Match Expression that can be used to transform
|
||||
the JSON response returned from the server.
|
||||
For example a JMESPath of "items | length(@)"
|
||||
applied to the API server response for
|
||||
the URLPath "/apis/apps/v1/deployments"
|
||||
will return the total count of deployments
|
||||
across all namespaces.
|
||||
type: string
|
||||
service:
|
||||
description: Service is an API call to a
|
||||
JSON web service
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is a PEM encoded
|
||||
CA bundle which will be used to validate
|
||||
the server certificate.
|
||||
type: string
|
||||
data:
|
||||
description: Data specifies the POST
|
||||
data sent to the server.
|
||||
items:
|
||||
description: RequestData contains
|
||||
the HTTP POST data
|
||||
properties:
|
||||
key:
|
||||
description: Key is a unique identifier
|
||||
for the data value
|
||||
type: string
|
||||
value:
|
||||
description: Value is the data
|
||||
value
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
requestType:
|
||||
default: GET
|
||||
description: Method is the HTTP request
|
||||
type (GET or POST).
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
type: string
|
||||
urlPath:
|
||||
description: URL is the JSON web service
|
||||
URL. The typical format is `https://{service}.{namespace}:{port}/{path}`.
|
||||
type: string
|
||||
required:
|
||||
- requestType
|
||||
- urlPath
|
||||
type: object
|
||||
urlPath:
|
||||
description: URLPath is the URL path to
|
||||
be used in the HTTP GET request to the
|
||||
Kubernetes API server (e.g. "/api/v1/namespaces"
|
||||
or "/apis/apps/v1/deployments"). The
|
||||
format required is the same format used
|
||||
by the `kubectl get --raw` command.
|
||||
type: string
|
||||
type: object
|
||||
configMap:
|
||||
description: ConfigMap is the ConfigMap reference.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the ConfigMap name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the ConfigMap
|
||||
namespace.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
imageRegistry:
|
||||
description: ImageRegistry defines requests
|
||||
to an OCI/Docker V2 registry to fetch image
|
||||
details.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JSON
|
||||
Match Expression that can be used to transform
|
||||
the ImageData struct returned as a result
|
||||
of processing the image reference.
|
||||
type: string
|
||||
reference:
|
||||
description: 'Reference is image reference
|
||||
to a container image in the registry.
|
||||
Example: ghcr.io/kyverno/kyverno:latest'
|
||||
type: string
|
||||
required:
|
||||
- reference
|
||||
type: object
|
||||
name:
|
||||
description: Name is the variable name.
|
||||
type: string
|
||||
variable:
|
||||
description: Variable defines an arbitrary JMESPath
|
||||
context variable that can be defined inline.
|
||||
properties:
|
||||
default:
|
||||
description: Default is an optional arbitrary
|
||||
JSON object that the variable may take
|
||||
if the JMESPath expression evaluates to
|
||||
nil
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JMESPath
|
||||
Expression that can be used to transform
|
||||
the variable.
|
||||
type: string
|
||||
value:
|
||||
description: Value is any arbitrary JSON
|
||||
object representable in YAML or JSON form.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
|
@ -2074,6 +2211,15 @@ spec:
|
|||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
preconditions:
|
||||
description: 'Preconditions are used to determine
|
||||
if a policy rule should be applied by evaluating
|
||||
a set of conditions. The declaration can contain
|
||||
nested `any` or `all` statements. A direct list
|
||||
of conditions (without `any` or `all` statements
|
||||
is supported for backwards compatibility but will
|
||||
be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/'
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
|
@ -5478,10 +5624,155 @@ spec:
|
|||
description: Targets defines the target resources to
|
||||
be mutated.
|
||||
items:
|
||||
description: TargetResourceSpec defines targets for
|
||||
mutating existing resources.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
context:
|
||||
description: Context defines variables and data
|
||||
sources that can be used during rule execution.
|
||||
items:
|
||||
description: ContextEntry adds variables and
|
||||
data sources to a rule Context. Either a ConfigMap
|
||||
reference or a APILookup must be provided.
|
||||
properties:
|
||||
apiCall:
|
||||
description: APICall is an HTTP request
|
||||
to the Kubernetes API server, or other
|
||||
JSON web service. The data returned is
|
||||
stored in the context with the name for
|
||||
the context entry.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JSON Match Expression that can be
|
||||
used to transform the JSON response
|
||||
returned from the server. For example
|
||||
a JMESPath of "items | length(@)"
|
||||
applied to the API server response
|
||||
for the URLPath "/apis/apps/v1/deployments"
|
||||
will return the total count of deployments
|
||||
across all namespaces.
|
||||
type: string
|
||||
service:
|
||||
description: Service is an API call
|
||||
to a JSON web service
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is a PEM encoded
|
||||
CA bundle which will be used to
|
||||
validate the server certificate.
|
||||
type: string
|
||||
data:
|
||||
description: Data specifies the
|
||||
POST data sent to the server.
|
||||
items:
|
||||
description: RequestData contains
|
||||
the HTTP POST data
|
||||
properties:
|
||||
key:
|
||||
description: Key is a unique
|
||||
identifier for the data
|
||||
value
|
||||
type: string
|
||||
value:
|
||||
description: Value is the
|
||||
data value
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
requestType:
|
||||
default: GET
|
||||
description: Method is the HTTP
|
||||
request type (GET or POST).
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
type: string
|
||||
urlPath:
|
||||
description: URL is the JSON web
|
||||
service URL. The typical format
|
||||
is `https://{service}.{namespace}:{port}/{path}`.
|
||||
type: string
|
||||
required:
|
||||
- requestType
|
||||
- urlPath
|
||||
type: object
|
||||
urlPath:
|
||||
description: URLPath is the URL path
|
||||
to be used in the HTTP GET request
|
||||
to the Kubernetes API server (e.g.
|
||||
"/api/v1/namespaces" or "/apis/apps/v1/deployments").
|
||||
The format required is the same format
|
||||
used by the `kubectl get --raw` command.
|
||||
type: string
|
||||
type: object
|
||||
configMap:
|
||||
description: ConfigMap is the ConfigMap
|
||||
reference.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the ConfigMap name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the ConfigMap
|
||||
namespace.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
imageRegistry:
|
||||
description: ImageRegistry defines requests
|
||||
to an OCI/Docker V2 registry to fetch
|
||||
image details.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JSON Match Expression that can be
|
||||
used to transform the ImageData struct
|
||||
returned as a result of processing
|
||||
the image reference.
|
||||
type: string
|
||||
reference:
|
||||
description: 'Reference is image reference
|
||||
to a container image in the registry.
|
||||
Example: ghcr.io/kyverno/kyverno:latest'
|
||||
type: string
|
||||
required:
|
||||
- reference
|
||||
type: object
|
||||
name:
|
||||
description: Name is the variable name.
|
||||
type: string
|
||||
variable:
|
||||
description: Variable defines an arbitrary
|
||||
JMESPath context variable that can be
|
||||
defined inline.
|
||||
properties:
|
||||
default:
|
||||
description: Default is an optional
|
||||
arbitrary JSON object that the variable
|
||||
may take if the JMESPath expression
|
||||
evaluates to nil
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JMESPath Expression that can be used
|
||||
to transform the variable.
|
||||
type: string
|
||||
value:
|
||||
description: Value is any arbitrary
|
||||
JSON object representable in YAML
|
||||
or JSON form.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
|
@ -5491,6 +5782,16 @@ spec:
|
|||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
preconditions:
|
||||
description: 'Preconditions are used to determine
|
||||
if a policy rule should be applied by evaluating
|
||||
a set of conditions. The declaration can contain
|
||||
nested `any` or `all` statements. A direct list
|
||||
of conditions (without `any` or `all` statements
|
||||
is supported for backwards compatibility but
|
||||
will be deprecated in the next major release.
|
||||
See: https://kyverno.io/docs/writing-policies/preconditions/'
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
|
@ -8539,10 +8840,147 @@ spec:
|
|||
description: Targets defines the target resources to be
|
||||
mutated.
|
||||
items:
|
||||
description: TargetResourceSpec defines targets for mutating
|
||||
existing resources.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
context:
|
||||
description: Context defines variables and data sources
|
||||
that can be used during rule execution.
|
||||
items:
|
||||
description: ContextEntry adds variables and data
|
||||
sources to a rule Context. Either a ConfigMap
|
||||
reference or a APILookup must be provided.
|
||||
properties:
|
||||
apiCall:
|
||||
description: APICall is an HTTP request to the
|
||||
Kubernetes API server, or other JSON web service.
|
||||
The data returned is stored in the context
|
||||
with the name for the context entry.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JSON
|
||||
Match Expression that can be used to transform
|
||||
the JSON response returned from the server.
|
||||
For example a JMESPath of "items | length(@)"
|
||||
applied to the API server response for
|
||||
the URLPath "/apis/apps/v1/deployments"
|
||||
will return the total count of deployments
|
||||
across all namespaces.
|
||||
type: string
|
||||
service:
|
||||
description: Service is an API call to a
|
||||
JSON web service
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is a PEM encoded
|
||||
CA bundle which will be used to validate
|
||||
the server certificate.
|
||||
type: string
|
||||
data:
|
||||
description: Data specifies the POST
|
||||
data sent to the server.
|
||||
items:
|
||||
description: RequestData contains
|
||||
the HTTP POST data
|
||||
properties:
|
||||
key:
|
||||
description: Key is a unique identifier
|
||||
for the data value
|
||||
type: string
|
||||
value:
|
||||
description: Value is the data
|
||||
value
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
requestType:
|
||||
default: GET
|
||||
description: Method is the HTTP request
|
||||
type (GET or POST).
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
type: string
|
||||
urlPath:
|
||||
description: URL is the JSON web service
|
||||
URL. The typical format is `https://{service}.{namespace}:{port}/{path}`.
|
||||
type: string
|
||||
required:
|
||||
- requestType
|
||||
- urlPath
|
||||
type: object
|
||||
urlPath:
|
||||
description: URLPath is the URL path to
|
||||
be used in the HTTP GET request to the
|
||||
Kubernetes API server (e.g. "/api/v1/namespaces"
|
||||
or "/apis/apps/v1/deployments"). The
|
||||
format required is the same format used
|
||||
by the `kubectl get --raw` command.
|
||||
type: string
|
||||
type: object
|
||||
configMap:
|
||||
description: ConfigMap is the ConfigMap reference.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the ConfigMap name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the ConfigMap
|
||||
namespace.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
imageRegistry:
|
||||
description: ImageRegistry defines requests
|
||||
to an OCI/Docker V2 registry to fetch image
|
||||
details.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JSON
|
||||
Match Expression that can be used to transform
|
||||
the ImageData struct returned as a result
|
||||
of processing the image reference.
|
||||
type: string
|
||||
reference:
|
||||
description: 'Reference is image reference
|
||||
to a container image in the registry.
|
||||
Example: ghcr.io/kyverno/kyverno:latest'
|
||||
type: string
|
||||
required:
|
||||
- reference
|
||||
type: object
|
||||
name:
|
||||
description: Name is the variable name.
|
||||
type: string
|
||||
variable:
|
||||
description: Variable defines an arbitrary JMESPath
|
||||
context variable that can be defined inline.
|
||||
properties:
|
||||
default:
|
||||
description: Default is an optional arbitrary
|
||||
JSON object that the variable may take
|
||||
if the JMESPath expression evaluates to
|
||||
nil
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
jmesPath:
|
||||
description: JMESPath is an optional JMESPath
|
||||
Expression that can be used to transform
|
||||
the variable.
|
||||
type: string
|
||||
value:
|
||||
description: Value is any arbitrary JSON
|
||||
object representable in YAML or JSON form.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
|
@ -8552,6 +8990,15 @@ spec:
|
|||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
preconditions:
|
||||
description: 'Preconditions are used to determine
|
||||
if a policy rule should be applied by evaluating
|
||||
a set of conditions. The declaration can contain
|
||||
nested `any` or `all` statements. A direct list
|
||||
of conditions (without `any` or `all` statements
|
||||
is supported for backwards compatibility but will
|
||||
be deprecated in the next major release. See: https://kyverno.io/docs/writing-policies/preconditions/'
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
|
@ -12083,10 +12530,155 @@ spec:
|
|||
description: Targets defines the target resources to
|
||||
be mutated.
|
||||
items:
|
||||
description: TargetResourceSpec defines targets for
|
||||
mutating existing resources.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
type: string
|
||||
context:
|
||||
description: Context defines variables and data
|
||||
sources that can be used during rule execution.
|
||||
items:
|
||||
description: ContextEntry adds variables and
|
||||
data sources to a rule Context. Either a ConfigMap
|
||||
reference or a APILookup must be provided.
|
||||
properties:
|
||||
apiCall:
|
||||
description: APICall is an HTTP request
|
||||
to the Kubernetes API server, or other
|
||||
JSON web service. The data returned is
|
||||
stored in the context with the name for
|
||||
the context entry.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JSON Match Expression that can be
|
||||
used to transform the JSON response
|
||||
returned from the server. For example
|
||||
a JMESPath of "items | length(@)"
|
||||
applied to the API server response
|
||||
for the URLPath "/apis/apps/v1/deployments"
|
||||
will return the total count of deployments
|
||||
across all namespaces.
|
||||
type: string
|
||||
service:
|
||||
description: Service is an API call
|
||||
to a JSON web service
|
||||
properties:
|
||||
caBundle:
|
||||
description: CABundle is a PEM encoded
|
||||
CA bundle which will be used to
|
||||
validate the server certificate.
|
||||
type: string
|
||||
data:
|
||||
description: Data specifies the
|
||||
POST data sent to the server.
|
||||
items:
|
||||
description: RequestData contains
|
||||
the HTTP POST data
|
||||
properties:
|
||||
key:
|
||||
description: Key is a unique
|
||||
identifier for the data
|
||||
value
|
||||
type: string
|
||||
value:
|
||||
description: Value is the
|
||||
data value
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
type: object
|
||||
type: array
|
||||
requestType:
|
||||
default: GET
|
||||
description: Method is the HTTP
|
||||
request type (GET or POST).
|
||||
enum:
|
||||
- GET
|
||||
- POST
|
||||
type: string
|
||||
urlPath:
|
||||
description: URL is the JSON web
|
||||
service URL. The typical format
|
||||
is `https://{service}.{namespace}:{port}/{path}`.
|
||||
type: string
|
||||
required:
|
||||
- requestType
|
||||
- urlPath
|
||||
type: object
|
||||
urlPath:
|
||||
description: URLPath is the URL path
|
||||
to be used in the HTTP GET request
|
||||
to the Kubernetes API server (e.g.
|
||||
"/api/v1/namespaces" or "/apis/apps/v1/deployments").
|
||||
The format required is the same format
|
||||
used by the `kubectl get --raw` command.
|
||||
type: string
|
||||
type: object
|
||||
configMap:
|
||||
description: ConfigMap is the ConfigMap
|
||||
reference.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the ConfigMap name.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the ConfigMap
|
||||
namespace.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
imageRegistry:
|
||||
description: ImageRegistry defines requests
|
||||
to an OCI/Docker V2 registry to fetch
|
||||
image details.
|
||||
properties:
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JSON Match Expression that can be
|
||||
used to transform the ImageData struct
|
||||
returned as a result of processing
|
||||
the image reference.
|
||||
type: string
|
||||
reference:
|
||||
description: 'Reference is image reference
|
||||
to a container image in the registry.
|
||||
Example: ghcr.io/kyverno/kyverno:latest'
|
||||
type: string
|
||||
required:
|
||||
- reference
|
||||
type: object
|
||||
name:
|
||||
description: Name is the variable name.
|
||||
type: string
|
||||
variable:
|
||||
description: Variable defines an arbitrary
|
||||
JMESPath context variable that can be
|
||||
defined inline.
|
||||
properties:
|
||||
default:
|
||||
description: Default is an optional
|
||||
arbitrary JSON object that the variable
|
||||
may take if the JMESPath expression
|
||||
evaluates to nil
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
jmesPath:
|
||||
description: JMESPath is an optional
|
||||
JMESPath Expression that can be used
|
||||
to transform the variable.
|
||||
type: string
|
||||
value:
|
||||
description: Value is any arbitrary
|
||||
JSON object representable in YAML
|
||||
or JSON form.
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: object
|
||||
type: array
|
||||
kind:
|
||||
description: Kind specifies resource kind.
|
||||
type: string
|
||||
|
@ -12096,6 +12688,16 @@ spec:
|
|||
namespace:
|
||||
description: Namespace specifies resource namespace.
|
||||
type: string
|
||||
preconditions:
|
||||
description: 'Preconditions are used to determine
|
||||
if a policy rule should be applied by evaluating
|
||||
a set of conditions. The declaration can contain
|
||||
nested `any` or `all` statements. A direct list
|
||||
of conditions (without `any` or `all` statements
|
||||
is supported for backwards compatibility but
|
||||
will be deprecated in the next major release.
|
||||
See: https://kyverno.io/docs/writing-policies/preconditions/'
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1153,6 +1153,7 @@ string
|
|||
<a href="#kyverno.io/v1.ForEachMutation">ForEachMutation</a>,
|
||||
<a href="#kyverno.io/v1.ForEachValidation">ForEachValidation</a>,
|
||||
<a href="#kyverno.io/v1.Rule">Rule</a>,
|
||||
<a href="#kyverno.io/v1.TargetResourceSpec">TargetResourceSpec</a>,
|
||||
<a href="#kyverno.io/v2beta1.Rule">Rule</a>)
|
||||
</p>
|
||||
<p>
|
||||
|
@ -2299,8 +2300,8 @@ Please specify under “any” or “all” instead.</p>
|
|||
<td>
|
||||
<code>targets</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v1.ResourceSpec">
|
||||
[]ResourceSpec
|
||||
<a href="#kyverno.io/v1.TargetResourceSpec">
|
||||
[]TargetResourceSpec
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -2819,7 +2820,7 @@ ResourceDescription
|
|||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v1.Generation">Generation</a>,
|
||||
<a href="#kyverno.io/v1.Mutation">Mutation</a>,
|
||||
<a href="#kyverno.io/v1.TargetResourceSpec">TargetResourceSpec</a>,
|
||||
<a href="#kyverno.io/v1beta1.UpdateRequestSpec">UpdateRequestSpec</a>,
|
||||
<a href="#kyverno.io/v1beta1.UpdateRequestStatus">UpdateRequestStatus</a>)
|
||||
</p>
|
||||
|
@ -3495,6 +3496,71 @@ Rekor (<a href="https://rekor.sigstore.dev">https://rekor.sigstore.dev</a>) is u
|
|||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v1.TargetResourceSpec">TargetResourceSpec
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v1.Mutation">Mutation</a>)
|
||||
</p>
|
||||
<p>
|
||||
<p>TargetResourceSpec defines targets for mutating existing resources.</p>
|
||||
</p>
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>ResourceSpec</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v1.ResourceSpec">
|
||||
ResourceSpec
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>ResourceSpec contains the target resources to load when mutating existing resources.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>context</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v1.ContextEntry">
|
||||
[]ContextEntry
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Context defines variables and data sources that can be used during rule execution.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>preconditions</code><br/>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#json-v1-apiextensions">
|
||||
Kubernetes apiextensions/v1.JSON
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Preconditions are used to determine if a policy rule should be applied by evaluating a
|
||||
set of conditions. The declaration can contain nested <code>any</code> or <code>all</code> statements. A direct list
|
||||
of conditions (without <code>any</code> or <code>all</code> statements is supported for backwards compatibility but
|
||||
will be deprecated in the next major release.
|
||||
See: <a href="https://kyverno.io/docs/writing-policies/preconditions/">https://kyverno.io/docs/writing-policies/preconditions/</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v1.UserInfo">UserInfo
|
||||
</h3>
|
||||
<p>
|
||||
|
|
|
@ -6,14 +6,13 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
gojmespath "github.com/jmespath/go-jmespath"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers/mutation"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers/validation"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
|
@ -24,19 +23,15 @@ import (
|
|||
)
|
||||
|
||||
type engine struct {
|
||||
configuration config.Configuration
|
||||
client dclient.Interface
|
||||
rclient registryclient.Client
|
||||
engineContextLoaderFactory engineapi.EngineContextLoaderFactory
|
||||
exceptionSelector engineapi.PolicyExceptionSelector
|
||||
validateResourceHandler handlers.Handler
|
||||
validateManifestHandler handlers.Handler
|
||||
validatePssHandler handlers.Handler
|
||||
validateImageHandler handlers.Handler
|
||||
mutateResourceHandler handlers.Handler
|
||||
mutateExistingHandler handlers.Handler
|
||||
configuration config.Configuration
|
||||
client dclient.Interface
|
||||
rclient registryclient.Client
|
||||
contextLoader engineapi.ContextLoaderFactory
|
||||
exceptionSelector engineapi.PolicyExceptionSelector
|
||||
}
|
||||
|
||||
type handlerFactory = func() (handlers.Handler, error)
|
||||
|
||||
func NewEngine(
|
||||
configuration config.Configuration,
|
||||
client dclient.Interface,
|
||||
|
@ -44,30 +39,12 @@ func NewEngine(
|
|||
contextLoader engineapi.ContextLoaderFactory,
|
||||
exceptionSelector engineapi.PolicyExceptionSelector,
|
||||
) engineapi.Engine {
|
||||
engineContextLoaderFactory := func(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule) engineapi.EngineContextLoader {
|
||||
loader := contextLoader(policy, rule)
|
||||
return func(ctx context.Context, contextEntries []kyvernov1.ContextEntry, jsonContext enginecontext.Interface) error {
|
||||
return loader.Load(
|
||||
ctx,
|
||||
client,
|
||||
rclient,
|
||||
contextEntries,
|
||||
jsonContext,
|
||||
)
|
||||
}
|
||||
}
|
||||
return &engine{
|
||||
configuration: configuration,
|
||||
client: client,
|
||||
rclient: rclient,
|
||||
engineContextLoaderFactory: engineContextLoaderFactory,
|
||||
exceptionSelector: exceptionSelector,
|
||||
validateResourceHandler: validation.NewValidateResourceHandler(),
|
||||
validateManifestHandler: validation.NewValidateManifestHandler(client),
|
||||
validatePssHandler: validation.NewValidatePssHandler(),
|
||||
validateImageHandler: validation.NewValidateImageHandler(configuration),
|
||||
mutateResourceHandler: mutation.NewMutateResourceHandler(),
|
||||
mutateExistingHandler: mutation.NewMutateExistingHandler(client),
|
||||
configuration: configuration,
|
||||
client: client,
|
||||
rclient: rclient,
|
||||
contextLoader: contextLoader,
|
||||
exceptionSelector: exceptionSelector,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,7 +120,16 @@ func (e *engine) ContextLoader(
|
|||
policy kyvernov1.PolicyInterface,
|
||||
rule kyvernov1.Rule,
|
||||
) engineapi.EngineContextLoader {
|
||||
return e.engineContextLoaderFactory(policy, rule)
|
||||
loader := e.contextLoader(policy, rule)
|
||||
return func(ctx context.Context, contextEntries []kyvernov1.ContextEntry, jsonContext enginecontext.Interface) error {
|
||||
return loader.Load(
|
||||
ctx,
|
||||
e.client,
|
||||
e.rclient,
|
||||
contextEntries,
|
||||
jsonContext,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// matches checks if either the new or old resource satisfies the filter conditions defined in the rule
|
||||
|
@ -188,7 +174,7 @@ func matches(
|
|||
func (e *engine) invokeRuleHandler(
|
||||
ctx context.Context,
|
||||
logger logr.Logger,
|
||||
handler handlers.Handler,
|
||||
handlerFactory handlerFactory,
|
||||
policyContext engineapi.PolicyContext,
|
||||
resource unstructured.Unstructured,
|
||||
rule kyvernov1.Rule,
|
||||
|
@ -204,12 +190,37 @@ func (e *engine) invokeRuleHandler(
|
|||
logger.V(4).Info("rule not matched", "reason", err.Error())
|
||||
return resource, nil
|
||||
}
|
||||
// check if there's an exception
|
||||
if ruleResp := e.hasPolicyExceptions(logger, ruleType, policyContext, rule); ruleResp != nil {
|
||||
return resource, handlers.RuleResponses(ruleResp)
|
||||
if handlerFactory == nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, ruleType, "failed to instantiate handler", nil))
|
||||
} else if handler, err := handlerFactory(); err != nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, ruleType, "failed to instantiate handler", err))
|
||||
} else if handler != nil {
|
||||
// check if there's an exception
|
||||
if ruleResp := e.hasPolicyExceptions(logger, ruleType, policyContext, rule); ruleResp != nil {
|
||||
return resource, handlers.RuleResponses(ruleResp)
|
||||
}
|
||||
// load rule context
|
||||
contextLoader := e.ContextLoader(policyContext.Policy(), rule)
|
||||
if err := contextLoader(ctx, rule.Context, policyContext.JSONContext()); err != nil {
|
||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||
logger.V(3).Info("failed to load context", "reason", err.Error())
|
||||
} else {
|
||||
logger.Error(err, "failed to load context")
|
||||
}
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, ruleType, "failed to load context", err))
|
||||
}
|
||||
// check preconditions
|
||||
preconditionsPassed, err := internal.CheckPreconditions(logger, policyContext.JSONContext(), rule.GetAnyAllConditions())
|
||||
if err != nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, ruleType, "failed to evaluate preconditions", err))
|
||||
}
|
||||
if !preconditionsPassed {
|
||||
return resource, handlers.RuleResponses(internal.RuleSkip(rule, ruleType, "preconditions not met"))
|
||||
}
|
||||
// process handler
|
||||
return handler.Process(ctx, logger, policyContext, resource, rule, contextLoader)
|
||||
}
|
||||
// process handler
|
||||
return handler.Process(ctx, logger, policyContext, resource, rule, e.ContextLoader(policyContext.Policy(), rule))
|
||||
return resource, nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -14,36 +14,14 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func mutateResource(
|
||||
ctx context.Context,
|
||||
contextLoader engineapi.EngineContextLoader,
|
||||
rule kyvernov1.Rule,
|
||||
policyContext engineapi.PolicyContext,
|
||||
resource unstructured.Unstructured,
|
||||
logger logr.Logger,
|
||||
) *mutate.Response {
|
||||
if err := contextLoader(ctx, rule.Context, policyContext.JSONContext()); err != nil {
|
||||
logger.Error(err, "failed to load context")
|
||||
return mutate.NewErrorResponse("failed to load context", err)
|
||||
}
|
||||
preconditionsPassed, err := internal.CheckPreconditions(logger, policyContext.JSONContext(), rule.GetAnyAllConditions())
|
||||
if err != nil {
|
||||
return mutate.NewErrorResponse("failed to evaluate preconditions", err)
|
||||
}
|
||||
if !preconditionsPassed {
|
||||
return mutate.NewResponse(engineapi.RuleStatusSkip, resource, nil, "preconditions not met")
|
||||
}
|
||||
return mutate.Mutate(&rule, policyContext.JSONContext(), resource, logger)
|
||||
}
|
||||
|
||||
type forEachMutator struct {
|
||||
rule *kyvernov1.Rule
|
||||
logger logr.Logger
|
||||
rule kyvernov1.Rule
|
||||
policyContext engineapi.PolicyContext
|
||||
foreach []kyvernov1.ForEachMutation
|
||||
resource resourceInfo
|
||||
nesting int
|
||||
contextLoader engineapi.EngineContextLoader
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
func (f *forEachMutator) mutateForEach(ctx context.Context) *mutate.Response {
|
||||
|
@ -51,20 +29,6 @@ func (f *forEachMutator) mutateForEach(ctx context.Context) *mutate.Response {
|
|||
allPatches := make([][]byte, 0)
|
||||
|
||||
for _, foreach := range f.foreach {
|
||||
if err := f.contextLoader(ctx, f.rule.Context, f.policyContext.JSONContext()); err != nil {
|
||||
f.log.Error(err, "failed to load context")
|
||||
return mutate.NewErrorResponse("failed to load context", err)
|
||||
}
|
||||
|
||||
preconditionsPassed, err := internal.CheckPreconditions(f.log, f.policyContext.JSONContext(), f.rule.GetAnyAllConditions())
|
||||
if err != nil {
|
||||
return mutate.NewErrorResponse("failed to evaluate preconditions", err)
|
||||
}
|
||||
|
||||
if !preconditionsPassed {
|
||||
return mutate.NewResponse(engineapi.RuleStatusSkip, f.resource.unstructured, nil, "preconditions not met")
|
||||
}
|
||||
|
||||
elements, err := engineutils.EvaluateList(foreach.List, f.policyContext.JSONContext())
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("failed to evaluate list %s: %v", foreach.List, err)
|
||||
|
@ -82,9 +46,9 @@ func (f *forEachMutator) mutateForEach(ctx context.Context) *mutate.Response {
|
|||
f.resource.unstructured = mutateResp.PatchedResource
|
||||
allPatches = append(allPatches, mutateResp.Patches...)
|
||||
}
|
||||
f.log.Info("mutateResp.PatchedResource", "resource", mutateResp.PatchedResource)
|
||||
f.logger.Info("mutateResp.PatchedResource", "resource", mutateResp.PatchedResource)
|
||||
if err := f.policyContext.JSONContext().AddResource(mutateResp.PatchedResource.Object); err != nil {
|
||||
f.log.Error(err, "failed to update resource in context")
|
||||
f.logger.Error(err, "failed to update resource in context")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,13 +88,13 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
|
|||
return mutate.NewErrorResponse(fmt.Sprintf("failed to load to mutate.foreach[%d].context", index), err)
|
||||
}
|
||||
|
||||
preconditionsPassed, err := internal.CheckPreconditions(f.log, policyContext.JSONContext(), foreach.AnyAllConditions)
|
||||
preconditionsPassed, err := internal.CheckPreconditions(f.logger, policyContext.JSONContext(), foreach.AnyAllConditions)
|
||||
if err != nil {
|
||||
return mutate.NewErrorResponse(fmt.Sprintf("failed to evaluate mutate.foreach[%d].preconditions", index), err)
|
||||
}
|
||||
|
||||
if !preconditionsPassed {
|
||||
f.log.Info("mutate.foreach.preconditions not met", "elementIndex", index)
|
||||
f.logger.Info("mutate.foreach.preconditions not met", "elementIndex", index)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -145,7 +109,7 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
|
|||
rule: f.rule,
|
||||
policyContext: f.policyContext,
|
||||
resource: patchedResource,
|
||||
log: f.log,
|
||||
logger: f.logger,
|
||||
foreach: nestedForEach,
|
||||
nesting: f.nesting + 1,
|
||||
contextLoader: f.contextLoader,
|
||||
|
@ -153,7 +117,7 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
|
|||
|
||||
mutateResp = m.mutateForEach(ctx)
|
||||
} else {
|
||||
mutateResp = mutate.ForEach(f.rule.Name, foreach, policyContext, patchedResource.unstructured, element, f.log)
|
||||
mutateResp = mutate.ForEach(f.rule.Name, foreach, policyContext, patchedResource.unstructured, element, f.logger)
|
||||
}
|
||||
|
||||
if mutateResp.Status == engineapi.RuleStatusFail || mutateResp.Status == engineapi.RuleStatusError {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
"github.com/kyverno/kyverno/pkg/utils/wildcard"
|
||||
"go.uber.org/multierr"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
@ -24,10 +25,17 @@ type resourceInfo struct {
|
|||
parentResourceGVR metav1.GroupVersionResource
|
||||
}
|
||||
|
||||
func loadTargets(client dclient.Interface, targets []kyvernov1.ResourceSpec, ctx engineapi.PolicyContext, logger logr.Logger) ([]resourceInfo, error) {
|
||||
var targetObjects []resourceInfo
|
||||
type target struct {
|
||||
resourceInfo
|
||||
context []kyvernov1.ContextEntry
|
||||
preconditions apiextensions.JSON
|
||||
}
|
||||
|
||||
func loadTargets(client dclient.Interface, targets []kyvernov1.TargetResourceSpec, ctx engineapi.PolicyContext, logger logr.Logger) ([]target, error) {
|
||||
var targetObjects []target
|
||||
var errors []error
|
||||
for i := range targets {
|
||||
preconditions := targets[i].GetAnyAllConditions()
|
||||
spec, err := resolveSpec(i, targets[i], ctx, logger)
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
|
@ -38,12 +46,18 @@ func loadTargets(client dclient.Interface, targets []kyvernov1.ResourceSpec, ctx
|
|||
errors = append(errors, err)
|
||||
continue
|
||||
}
|
||||
targetObjects = append(targetObjects, objs...)
|
||||
for _, obj := range objs {
|
||||
targetObjects = append(targetObjects, target{
|
||||
resourceInfo: obj,
|
||||
context: targets[i].Context,
|
||||
preconditions: preconditions,
|
||||
})
|
||||
}
|
||||
}
|
||||
return targetObjects, multierr.Combine(errors...)
|
||||
}
|
||||
|
||||
func resolveSpec(i int, target kyvernov1.ResourceSpec, ctx engineapi.PolicyContext, logger logr.Logger) (kyvernov1.ResourceSpec, error) {
|
||||
func resolveSpec(i int, target kyvernov1.TargetResourceSpec, ctx engineapi.PolicyContext, logger logr.Logger) (kyvernov1.ResourceSpec, error) {
|
||||
kind, err := variables.SubstituteAll(logger, ctx.JSONContext(), target.Kind)
|
||||
if err != nil {
|
||||
return kyvernov1.ResourceSpec{}, fmt.Errorf("failed to substitute variables in target[%d].Kind %s: %v", i, target.Kind, err)
|
||||
|
|
|
@ -19,10 +19,10 @@ type mutateExistingHandler struct {
|
|||
|
||||
func NewMutateExistingHandler(
|
||||
client dclient.Interface,
|
||||
) handlers.Handler {
|
||||
) (handlers.Handler, error) {
|
||||
return mutateExistingHandler{
|
||||
client: client,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h mutateExistingHandler) Process(
|
||||
|
@ -35,42 +35,57 @@ func (h mutateExistingHandler) Process(
|
|||
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
||||
var responses []engineapi.RuleResponse
|
||||
logger.V(3).Info("processing mutate rule")
|
||||
var patchedResources []resourceInfo
|
||||
targets, err := loadTargets(h.client, rule.Mutation.Targets, policyContext, logger)
|
||||
if err != nil {
|
||||
rr := internal.RuleError(rule, engineapi.Mutation, "", err)
|
||||
responses = append(responses, *rr)
|
||||
} else {
|
||||
patchedResources = append(patchedResources, targets...)
|
||||
}
|
||||
|
||||
for _, patchedResource := range patchedResources {
|
||||
if patchedResource.unstructured.Object == nil {
|
||||
for _, target := range targets {
|
||||
if target.unstructured.Object == nil {
|
||||
continue
|
||||
}
|
||||
policyContext := policyContext.Copy()
|
||||
if err := policyContext.JSONContext().AddTargetResource(patchedResource.unstructured.Object); err != nil {
|
||||
if err := policyContext.JSONContext().AddTargetResource(target.unstructured.Object); err != nil {
|
||||
logger.Error(err, "failed to add target resource to the context")
|
||||
continue
|
||||
}
|
||||
// load target specific context
|
||||
if err := contextLoader(ctx, target.context, policyContext.JSONContext()); err != nil {
|
||||
rr := internal.RuleError(rule, engineapi.Mutation, "failed to load context", err)
|
||||
responses = append(responses, *rr)
|
||||
continue
|
||||
}
|
||||
// load target specific preconditions
|
||||
preconditionsPassed, err := internal.CheckPreconditions(logger, policyContext.JSONContext(), target.preconditions)
|
||||
if err != nil {
|
||||
rr := internal.RuleError(rule, engineapi.Mutation, "failed to evaluate preconditions", err)
|
||||
responses = append(responses, *rr)
|
||||
continue
|
||||
}
|
||||
if !preconditionsPassed {
|
||||
rr := internal.RuleSkip(rule, engineapi.Mutation, "preconditions not met")
|
||||
responses = append(responses, *rr)
|
||||
continue
|
||||
}
|
||||
|
||||
// logger.V(4).Info("apply rule to resource", "resource namespace", patchedResource.unstructured.GetNamespace(), "resource name", patchedResource.unstructured.GetName())
|
||||
var mutateResp *mutate.Response
|
||||
if rule.Mutation.ForEachMutation != nil {
|
||||
m := &forEachMutator{
|
||||
rule: &rule,
|
||||
rule: rule,
|
||||
foreach: rule.Mutation.ForEachMutation,
|
||||
policyContext: policyContext,
|
||||
resource: patchedResource,
|
||||
log: logger,
|
||||
resource: target.resourceInfo,
|
||||
logger: logger,
|
||||
contextLoader: contextLoader,
|
||||
nesting: 0,
|
||||
}
|
||||
mutateResp = m.mutateForEach(ctx)
|
||||
} else {
|
||||
mutateResp = mutateResource(ctx, contextLoader, rule, policyContext, patchedResource.unstructured, logger)
|
||||
mutateResp = mutate.Mutate(&rule, policyContext.JSONContext(), target.unstructured, logger)
|
||||
}
|
||||
if ruleResponse := buildRuleResponse(&rule, mutateResp, patchedResource); ruleResponse != nil {
|
||||
if ruleResponse := buildRuleResponse(&rule, mutateResp, target.resourceInfo); ruleResponse != nil {
|
||||
responses = append(responses, *ruleResponse)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
gojmespath "github.com/jmespath/go-jmespath"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
|
@ -14,6 +13,7 @@ import (
|
|||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
|
@ -21,18 +21,33 @@ type mutateImageHandler struct {
|
|||
configuration config.Configuration
|
||||
rclient registryclient.Client
|
||||
ivm *engineapi.ImageVerificationMetadata
|
||||
images []apiutils.ImageInfo
|
||||
}
|
||||
|
||||
func NewMutateImageHandler(
|
||||
policyContext engineapi.PolicyContext,
|
||||
resource unstructured.Unstructured,
|
||||
rule kyvernov1.Rule,
|
||||
configuration config.Configuration,
|
||||
rclient registryclient.Client,
|
||||
ivm *engineapi.ImageVerificationMetadata,
|
||||
) handlers.Handler {
|
||||
) (handlers.Handler, error) {
|
||||
if len(rule.VerifyImages) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
ruleImages, _, err := engineutils.ExtractMatchingImages(resource, policyContext.JSONContext(), rule, configuration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ruleImages) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return mutateImageHandler{
|
||||
configuration: configuration,
|
||||
rclient: rclient,
|
||||
ivm: ivm,
|
||||
}
|
||||
images: ruleImages,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h mutateImageHandler) Process(
|
||||
|
@ -43,37 +58,7 @@ func (h mutateImageHandler) Process(
|
|||
rule kyvernov1.Rule,
|
||||
contextLoader engineapi.EngineContextLoader,
|
||||
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
||||
if engineutils.IsDeleteRequest(policyContext) {
|
||||
return resource, nil
|
||||
}
|
||||
if len(rule.VerifyImages) == 0 {
|
||||
return resource, nil
|
||||
}
|
||||
ruleImages, _, err := engineutils.ExtractMatchingImages(resource, policyContext.JSONContext(), rule, h.configuration)
|
||||
if err != nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.ImageVerify, "failed to extract images", err))
|
||||
}
|
||||
if len(ruleImages) == 0 {
|
||||
return resource, nil
|
||||
}
|
||||
jsonContext := policyContext.JSONContext()
|
||||
// load context
|
||||
if err := contextLoader(ctx, rule.Context, jsonContext); err != nil {
|
||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||
logger.V(3).Info("failed to load context", "reason", err.Error())
|
||||
} else {
|
||||
logger.Error(err, "failed to load context")
|
||||
}
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.ImageVerify, "failed to load context", err))
|
||||
}
|
||||
// check preconditions
|
||||
preconditionsPassed, err := internal.CheckPreconditions(logger, jsonContext, rule.GetAnyAllConditions())
|
||||
if err != nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.ImageVerify, "failed to evaluate preconditions", err))
|
||||
}
|
||||
if !preconditionsPassed {
|
||||
return resource, handlers.RuleResponses(internal.RuleSkip(rule, engineapi.ImageVerify, "preconditions not met"))
|
||||
}
|
||||
ruleCopy, err := substituteVariables(rule, jsonContext, logger)
|
||||
if err != nil {
|
||||
return resource, handlers.RuleResponses(
|
||||
|
@ -83,7 +68,7 @@ func (h mutateImageHandler) Process(
|
|||
iv := internal.NewImageVerifier(logger, h.rclient, policyContext, *ruleCopy, h.ivm)
|
||||
var engineResponses []*engineapi.RuleResponse
|
||||
for _, imageVerify := range ruleCopy.VerifyImages {
|
||||
engineResponses = append(engineResponses, iv.Verify(ctx, imageVerify, ruleImages, h.configuration)...)
|
||||
engineResponses = append(engineResponses, iv.Verify(ctx, imageVerify, h.images, h.configuration)...)
|
||||
}
|
||||
return resource, handlers.RuleResponses(engineResponses...)
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ import (
|
|||
|
||||
type mutateResourceHandler struct{}
|
||||
|
||||
func NewMutateResourceHandler() handlers.Handler {
|
||||
return mutateResourceHandler{}
|
||||
func NewMutateResourceHandler() (handlers.Handler, error) {
|
||||
return mutateResourceHandler{}, nil
|
||||
}
|
||||
|
||||
func (h mutateResourceHandler) Process(
|
||||
|
@ -41,17 +41,17 @@ func (h mutateResourceHandler) Process(
|
|||
var mutateResp *mutate.Response
|
||||
if rule.Mutation.ForEachMutation != nil {
|
||||
m := &forEachMutator{
|
||||
rule: &rule,
|
||||
rule: rule,
|
||||
foreach: rule.Mutation.ForEachMutation,
|
||||
policyContext: policyContext,
|
||||
resource: resourceInfo,
|
||||
log: logger,
|
||||
logger: logger,
|
||||
contextLoader: contextLoader,
|
||||
nesting: 0,
|
||||
}
|
||||
mutateResp = m.mutateForEach(ctx)
|
||||
} else {
|
||||
mutateResp = mutateResource(ctx, contextLoader, rule, policyContext, resourceInfo.unstructured, logger)
|
||||
mutateResp = mutate.Mutate(&rule, policyContext.JSONContext(), resource, logger)
|
||||
}
|
||||
if mutateResp == nil {
|
||||
return resource, nil
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
gojmespath "github.com/jmespath/go-jmespath"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
|
@ -16,16 +15,25 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
type validateImageHandler struct {
|
||||
configuration config.Configuration
|
||||
}
|
||||
type validateImageHandler struct{}
|
||||
|
||||
func NewValidateImageHandler(
|
||||
policyContext engineapi.PolicyContext,
|
||||
resource unstructured.Unstructured,
|
||||
rule kyvernov1.Rule,
|
||||
configuration config.Configuration,
|
||||
) handlers.Handler {
|
||||
return validateImageHandler{
|
||||
configuration: configuration,
|
||||
) (handlers.Handler, error) {
|
||||
if engineutils.IsDeleteRequest(policyContext) {
|
||||
return nil, nil
|
||||
}
|
||||
ruleImages, _, err := engineutils.ExtractMatchingImages(resource, policyContext.JSONContext(), rule, configuration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ruleImages) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return validateImageHandler{}, nil
|
||||
}
|
||||
|
||||
func (h validateImageHandler) Process(
|
||||
|
@ -34,41 +42,8 @@ func (h validateImageHandler) Process(
|
|||
policyContext engineapi.PolicyContext,
|
||||
resource unstructured.Unstructured,
|
||||
rule kyvernov1.Rule,
|
||||
contextLoader engineapi.EngineContextLoader,
|
||||
_ engineapi.EngineContextLoader,
|
||||
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
||||
if engineutils.IsDeleteRequest(policyContext) {
|
||||
return resource, nil
|
||||
}
|
||||
if len(rule.VerifyImages) == 0 {
|
||||
return resource, nil
|
||||
}
|
||||
ruleImages, _, err := engineutils.ExtractMatchingImages(resource, policyContext.JSONContext(), rule, h.configuration)
|
||||
if err != nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.Validation, "failed to extract images", err))
|
||||
}
|
||||
if len(ruleImages) == 0 {
|
||||
return resource, nil
|
||||
}
|
||||
// load context
|
||||
if err := contextLoader(ctx, rule.Context, policyContext.JSONContext()); err != nil {
|
||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||
logger.V(3).Info("failed to load context", "reason", err.Error())
|
||||
} else {
|
||||
logger.Error(err, "failed to load context")
|
||||
}
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.Validation, "failed to load context", err))
|
||||
}
|
||||
// check preconditions
|
||||
preconditionsPassed, err := internal.CheckPreconditions(logger, policyContext.JSONContext(), rule.GetAnyAllConditions())
|
||||
if err != nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.Validation, "failed to evaluate preconditions", err))
|
||||
}
|
||||
if !preconditionsPassed {
|
||||
if policyContext.Policy().GetSpec().ValidationFailureAction.Audit() {
|
||||
return resource, nil
|
||||
}
|
||||
return resource, handlers.RuleResponses(internal.RuleSkip(rule, engineapi.Validation, "preconditions not met"))
|
||||
}
|
||||
for _, v := range rule.VerifyImages {
|
||||
imageVerify := v.Convert()
|
||||
for _, infoMap := range policyContext.JSONContext().ImageInfo() {
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/go-logr/logr"
|
||||
gojmespath "github.com/jmespath/go-jmespath"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/auth"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
|
@ -39,10 +38,16 @@ type validateManifestHandler struct {
|
|||
client dclient.Interface
|
||||
}
|
||||
|
||||
func NewValidateManifestHandler(client dclient.Interface) handlers.Handler {
|
||||
func NewValidateManifestHandler(
|
||||
policyContext engineapi.PolicyContext,
|
||||
client dclient.Interface,
|
||||
) (handlers.Handler, error) {
|
||||
if engineutils.IsDeleteRequest(policyContext) {
|
||||
return nil, nil
|
||||
}
|
||||
return validateManifestHandler{
|
||||
client: client,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h validateManifestHandler) Process(
|
||||
|
@ -51,28 +56,8 @@ func (h validateManifestHandler) Process(
|
|||
policyContext engineapi.PolicyContext,
|
||||
resource unstructured.Unstructured,
|
||||
rule kyvernov1.Rule,
|
||||
contextLoader engineapi.EngineContextLoader,
|
||||
_ engineapi.EngineContextLoader,
|
||||
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
||||
if engineutils.IsDeleteRequest(policyContext) {
|
||||
return resource, nil
|
||||
}
|
||||
// load context
|
||||
if err := contextLoader(ctx, rule.Context, policyContext.JSONContext()); err != nil {
|
||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||
logger.V(3).Info("failed to load context", "reason", err.Error())
|
||||
} else {
|
||||
logger.Error(err, "failed to load context")
|
||||
}
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.Validation, "failed to load context", err))
|
||||
}
|
||||
// check preconditions
|
||||
preconditionsPassed, err := internal.CheckPreconditions(logger, policyContext.JSONContext(), rule.GetAnyAllConditions())
|
||||
if err != nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.Validation, "failed to evaluate preconditions", err))
|
||||
}
|
||||
if !preconditionsPassed {
|
||||
return resource, handlers.RuleResponses(internal.RuleSkip(rule, engineapi.Validation, "preconditions not met"))
|
||||
}
|
||||
// verify manifest
|
||||
verified, reason, err := h.verifyManifest(ctx, logger, policyContext, *rule.Validation.Manifests)
|
||||
if err != nil {
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
gojmespath "github.com/jmespath/go-jmespath"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||
|
@ -21,8 +20,8 @@ import (
|
|||
|
||||
type validatePssHandler struct{}
|
||||
|
||||
func NewValidatePssHandler() handlers.Handler {
|
||||
return validatePssHandler{}
|
||||
func NewValidatePssHandler() (handlers.Handler, error) {
|
||||
return validatePssHandler{}, nil
|
||||
}
|
||||
|
||||
func (h validatePssHandler) Process(
|
||||
|
@ -31,25 +30,8 @@ func (h validatePssHandler) Process(
|
|||
policyContext engineapi.PolicyContext,
|
||||
resource unstructured.Unstructured,
|
||||
rule kyvernov1.Rule,
|
||||
contextLoader engineapi.EngineContextLoader,
|
||||
_ engineapi.EngineContextLoader,
|
||||
) (unstructured.Unstructured, []engineapi.RuleResponse) {
|
||||
// load context
|
||||
if err := contextLoader(ctx, rule.Context, policyContext.JSONContext()); err != nil {
|
||||
if _, ok := err.(gojmespath.NotFoundError); ok {
|
||||
logger.V(3).Info("failed to load context", "reason", err.Error())
|
||||
} else {
|
||||
logger.Error(err, "failed to load context")
|
||||
}
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.Validation, "failed to load context", err))
|
||||
}
|
||||
// check preconditions
|
||||
preconditionsPassed, err := internal.CheckPreconditions(logger, policyContext.JSONContext(), rule.GetAnyAllConditions())
|
||||
if err != nil {
|
||||
return resource, handlers.RuleResponses(internal.RuleError(rule, engineapi.Validation, "failed to evaluate preconditions", err))
|
||||
}
|
||||
if !preconditionsPassed {
|
||||
return resource, handlers.RuleResponses(internal.RuleSkip(rule, engineapi.Validation, "preconditions not met"))
|
||||
}
|
||||
// Marshal pod metadata and spec
|
||||
podSecurity := rule.Validation.PodSecurity
|
||||
podSpec, metadata, err := getSpec(resource)
|
||||
|
|
|
@ -23,8 +23,8 @@ import (
|
|||
|
||||
type validateResourceHandler struct{}
|
||||
|
||||
func NewValidateResourceHandler() handlers.Handler {
|
||||
return validateResourceHandler{}
|
||||
func NewValidateResourceHandler() (handlers.Handler, error) {
|
||||
return validateResourceHandler{}, nil
|
||||
}
|
||||
|
||||
func (h validateResourceHandler) Process(
|
||||
|
@ -55,16 +55,14 @@ type validator struct {
|
|||
|
||||
func newValidator(log logr.Logger, contextLoader engineapi.EngineContextLoader, ctx engineapi.PolicyContext, rule kyvernov1.Rule) *validator {
|
||||
return &validator{
|
||||
log: log,
|
||||
rule: rule,
|
||||
policyContext: ctx,
|
||||
contextLoader: contextLoader,
|
||||
contextEntries: rule.Context,
|
||||
anyAllConditions: rule.GetAnyAllConditions(),
|
||||
pattern: rule.Validation.GetPattern(),
|
||||
anyPattern: rule.Validation.GetAnyPattern(),
|
||||
deny: rule.Validation.Deny,
|
||||
forEach: rule.Validation.ForEachValidation,
|
||||
log: log,
|
||||
rule: rule,
|
||||
policyContext: ctx,
|
||||
contextLoader: contextLoader,
|
||||
pattern: rule.Validation.GetPattern(),
|
||||
anyPattern: rule.Validation.GetAnyPattern(),
|
||||
deny: rule.Validation.Deny,
|
||||
forEach: rule.Validation.ForEachValidation,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers/mutation"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
)
|
||||
|
@ -29,18 +30,23 @@ func (e *engine) verifyAndPatchImages(
|
|||
for _, rule := range autogen.ComputeRules(policy) {
|
||||
startTime := time.Now()
|
||||
logger := internal.LoggerWithRule(logger, rule)
|
||||
if !rule.HasVerifyImages() {
|
||||
continue
|
||||
handlerFactory := func() (handlers.Handler, error) {
|
||||
if !rule.HasVerifyImages() {
|
||||
return nil, nil
|
||||
}
|
||||
return mutation.NewMutateImageHandler(
|
||||
policyContext,
|
||||
matchedResource,
|
||||
rule,
|
||||
e.configuration,
|
||||
e.rclient,
|
||||
&ivm,
|
||||
)
|
||||
}
|
||||
handler := mutation.NewMutateImageHandler(
|
||||
e.configuration,
|
||||
e.rclient,
|
||||
&ivm,
|
||||
)
|
||||
resource, ruleResp := e.invokeRuleHandler(
|
||||
ctx,
|
||||
logger,
|
||||
handler,
|
||||
handlerFactory,
|
||||
policyContext,
|
||||
matchedResource,
|
||||
rule,
|
||||
|
@ -56,6 +62,6 @@ func (e *engine) verifyAndPatchImages(
|
|||
break
|
||||
}
|
||||
}
|
||||
// TODO: i doesn't make sense to not return the patched resource here
|
||||
// TODO: it doesn't make sense to not return the patched resource here
|
||||
return resp, ivm
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers/mutation"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
@ -30,18 +31,19 @@ func (e *engine) mutate(
|
|||
for _, rule := range autogen.ComputeRules(policy) {
|
||||
startTime := time.Now()
|
||||
logger := internal.LoggerWithRule(logger, rule)
|
||||
if !rule.HasMutate() {
|
||||
continue
|
||||
}
|
||||
var handler handlers.Handler
|
||||
handler = e.mutateResourceHandler
|
||||
if !policyContext.AdmissionOperation() && rule.IsMutateExisting() {
|
||||
handler = e.mutateExistingHandler
|
||||
handlerFactory := func() (handlers.Handler, error) {
|
||||
if !rule.HasMutate() {
|
||||
return nil, nil
|
||||
}
|
||||
if !policyContext.AdmissionOperation() && rule.IsMutateExisting() {
|
||||
return mutation.NewMutateExistingHandler(e.client)
|
||||
}
|
||||
return mutation.NewMutateResourceHandler()
|
||||
}
|
||||
resource, ruleResp := e.invokeRuleHandler(
|
||||
ctx,
|
||||
logger,
|
||||
handler,
|
||||
handlerFactory,
|
||||
policyContext,
|
||||
matchedResource,
|
||||
rule,
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers/validation"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
)
|
||||
|
||||
|
@ -28,29 +29,39 @@ func (e *engine) validate(
|
|||
for _, rule := range autogen.ComputeRules(policy) {
|
||||
startTime := time.Now()
|
||||
logger := internal.LoggerWithRule(logger, rule)
|
||||
hasValidate := rule.HasValidate()
|
||||
hasVerifyImageChecks := rule.HasVerifyImageChecks()
|
||||
if !hasValidate && !hasVerifyImageChecks {
|
||||
continue
|
||||
}
|
||||
var handler handlers.Handler
|
||||
if hasValidate {
|
||||
hasVerifyManifest := rule.HasVerifyManifests()
|
||||
hasValidatePss := rule.HasValidatePodSecurity()
|
||||
if hasVerifyManifest {
|
||||
handler = e.validateManifestHandler
|
||||
} else if hasValidatePss {
|
||||
handler = e.validatePssHandler
|
||||
} else {
|
||||
handler = e.validateResourceHandler
|
||||
handlerFactory := func() (handlers.Handler, error) {
|
||||
hasValidate := rule.HasValidate()
|
||||
hasVerifyImageChecks := rule.HasVerifyImageChecks()
|
||||
if !hasValidate && !hasVerifyImageChecks {
|
||||
return nil, nil
|
||||
}
|
||||
} else if hasVerifyImageChecks {
|
||||
handler = e.validateImageHandler
|
||||
if hasValidate {
|
||||
hasVerifyManifest := rule.HasVerifyManifests()
|
||||
hasValidatePss := rule.HasValidatePodSecurity()
|
||||
if hasVerifyManifest {
|
||||
return validation.NewValidateManifestHandler(
|
||||
policyContext,
|
||||
e.client,
|
||||
)
|
||||
} else if hasValidatePss {
|
||||
return validation.NewValidatePssHandler()
|
||||
} else {
|
||||
return validation.NewValidateResourceHandler()
|
||||
}
|
||||
} else if hasVerifyImageChecks {
|
||||
return validation.NewValidateImageHandler(
|
||||
policyContext,
|
||||
policyContext.NewResource(),
|
||||
rule,
|
||||
e.configuration,
|
||||
)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
resource, ruleResp := e.invokeRuleHandler(
|
||||
ctx,
|
||||
logger,
|
||||
handler,
|
||||
handlerFactory,
|
||||
policyContext,
|
||||
matchedResource,
|
||||
rule,
|
||||
|
|
|
@ -90,7 +90,7 @@ func (m *Mutate) hasPatchesJSON6902() bool {
|
|||
return m.mutation.PatchesJSON6902 != ""
|
||||
}
|
||||
|
||||
func (m *Mutate) validateAuth(ctx context.Context, targets []kyvernov1.ResourceSpec) error {
|
||||
func (m *Mutate) validateAuth(ctx context.Context, targets []kyvernov1.TargetResourceSpec) error {
|
||||
var errs []error
|
||||
for _, target := range targets {
|
||||
if !regex.IsVariable(target.Namespace) {
|
||||
|
|
|
@ -39,14 +39,15 @@ import (
|
|||
"k8s.io/client-go/discovery"
|
||||
)
|
||||
|
||||
var allowedVariables = regexp.MustCompile(`request\.|serviceAccountName|serviceAccountNamespace|element|elementIndex|@|images\.|image\.|target\.|([a-z_0-9]+\()[^{}]`)
|
||||
|
||||
var allowedVariablesBackground = regexp.MustCompile(`request\.|element|elementIndex|@|images\.|image\.|target\.|([a-z_0-9]+\()[^{}]`)
|
||||
|
||||
// wildCardAllowedVariables represents regex for the allowed fields in wildcards
|
||||
var wildCardAllowedVariables = regexp.MustCompile(`\{\{\s*(request\.|serviceAccountName|serviceAccountNamespace)[^{}]*\}\}`)
|
||||
|
||||
var errOperationForbidden = errors.New("variables are forbidden in the path of a JSONPatch")
|
||||
var (
|
||||
allowedVariables = regexp.MustCompile(`request\.|serviceAccountName|serviceAccountNamespace|element|elementIndex|@|images\.|image\.|([a-z_0-9]+\()[^{}]`)
|
||||
allowedVariablesBackground = regexp.MustCompile(`request\.|element|elementIndex|@|images\.|image\.|([a-z_0-9]+\()[^{}]`)
|
||||
allowedVariablesInTarget = regexp.MustCompile(`request\.|serviceAccountName|serviceAccountNamespace|element|elementIndex|@|images\.|image\.|target\.|([a-z_0-9]+\()[^{}]`)
|
||||
allowedVariablesBackgroundInTarget = regexp.MustCompile(`request\.|element|elementIndex|@|images\.|image\.|target\.|([a-z_0-9]+\()[^{}]`)
|
||||
// wildCardAllowedVariables represents regex for the allowed fields in wildcards
|
||||
wildCardAllowedVariables = regexp.MustCompile(`\{\{\s*(request\.|serviceAccountName|serviceAccountNamespace)[^{}]*\}\}`)
|
||||
errOperationForbidden = errors.New("variables are forbidden in the path of a JSONPatch")
|
||||
)
|
||||
|
||||
// validateJSONPatchPathForForwardSlash checks for forward slash
|
||||
func validateJSONPatchPathForForwardSlash(patch string) error {
|
||||
|
@ -441,9 +442,22 @@ func hasInvalidVariables(policy kyvernov1.PolicyInterface, background bool) erro
|
|||
}
|
||||
}
|
||||
|
||||
ctx := buildContext(ruleCopy, background)
|
||||
if _, err := variables.SubstituteAllInRule(logging.GlobalLogger(), ctx, *ruleCopy); !variables.CheckNotFoundErr(err) {
|
||||
return fmt.Errorf("variable substitution failed for rule %s: %s", ruleCopy.Name, err.Error())
|
||||
// skip variable checks on mutate.targets, they will be validated separately
|
||||
withoutTargets := ruleCopy.DeepCopy()
|
||||
for i := range withoutTargets.Mutation.Targets {
|
||||
withoutTargets.Mutation.Targets[i].RawAnyAllConditions = nil
|
||||
}
|
||||
ctx := buildContext(withoutTargets, background, false, nil)
|
||||
if _, err := variables.SubstituteAllInRule(logging.GlobalLogger(), ctx, *withoutTargets); !variables.CheckNotFoundErr(err) {
|
||||
return fmt.Errorf("variable substitution failed for rule %s: %s", withoutTargets.Name, err.Error())
|
||||
}
|
||||
|
||||
// perform variable checks with mutate.targets
|
||||
for _, target := range r.Mutation.Targets {
|
||||
ctx := buildContext(ruleCopy, background, true, target.Context)
|
||||
if _, err := variables.SubstituteAllInRule(logging.GlobalLogger(), ctx, *ruleCopy); !variables.CheckNotFoundErr(err) {
|
||||
return fmt.Errorf("variable substitution failed for rule target %s: %s", ruleCopy.Name, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,29 +568,34 @@ func imageRefHasVariables(verifyImages []kyvernov1.ImageVerification) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func buildContext(rule *kyvernov1.Rule, background bool) *enginecontext.MockContext {
|
||||
re := getAllowedVariables(background)
|
||||
func buildContext(rule *kyvernov1.Rule, background bool, target bool, targetContext []kyvernov1.ContextEntry) *enginecontext.MockContext {
|
||||
re := getAllowedVariables(background, target)
|
||||
ctx := enginecontext.NewMockContext(re)
|
||||
|
||||
addContextVariables(rule.Context, ctx)
|
||||
|
||||
for _, fe := range rule.Validation.ForEachValidation {
|
||||
addContextVariables(fe.Context, ctx)
|
||||
}
|
||||
|
||||
for _, fe := range rule.Mutation.ForEachMutation {
|
||||
addContextVariables(fe.Context, ctx)
|
||||
}
|
||||
|
||||
for _, fe := range rule.Mutation.Targets {
|
||||
addContextVariables(fe.Context, ctx)
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
func getAllowedVariables(background bool) *regexp.Regexp {
|
||||
if background {
|
||||
return allowedVariablesBackground
|
||||
func getAllowedVariables(background bool, target bool) *regexp.Regexp {
|
||||
if target {
|
||||
if background {
|
||||
return allowedVariablesBackgroundInTarget
|
||||
}
|
||||
return allowedVariablesInTarget
|
||||
} else {
|
||||
if background {
|
||||
return allowedVariablesBackground
|
||||
}
|
||||
return allowedVariables
|
||||
}
|
||||
|
||||
return allowedVariables
|
||||
}
|
||||
|
||||
func addContextVariables(entries []kyvernov1.ContextEntry, ctx *enginecontext.MockContext) {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: resources.yaml
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- policy.yaml
|
||||
assert:
|
||||
- policy-assert.yaml
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: trigger.yaml
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
assert:
|
||||
- resources-assert.yaml
|
|
@ -0,0 +1,21 @@
|
|||
## Description
|
||||
|
||||
This test creates one `ConfigMap` named `target`.
|
||||
|
||||
It then creates a `ClusterPolicy` with a mutate existing rule targeting the previously created `ConfigMap`.
|
||||
|
||||
The policy rule uses `context` on the trigger resource to create a variable containing the value of `data.content`.
|
||||
The policy rule uses `context` on the target resource to create a variable containing the value of `data.content`.
|
||||
The policy mutates target resource, setting `data.content` to the value of the trigger resource level variable and `data.targetContent` to the value of the target resource level variable.
|
||||
|
||||
Finally, the test creates the trigger config map.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
The target config map should contain:
|
||||
|
||||
```yaml
|
||||
data:
|
||||
content: trigger
|
||||
targetContent: target
|
||||
```
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: update-targets
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
|
@ -0,0 +1,36 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: update-targets
|
||||
spec:
|
||||
background: false
|
||||
rules:
|
||||
- name: update-targets
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- ConfigMap
|
||||
context:
|
||||
- name: triggerContent
|
||||
variable:
|
||||
jmesPath: request.object.data.content
|
||||
preconditions:
|
||||
all:
|
||||
- key: "{{ request.object.metadata.name }}"
|
||||
operator: Equals
|
||||
value: trigger
|
||||
mutate:
|
||||
targets:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
namespace: "{{ request.object.metadata.namespace }}"
|
||||
name: target*
|
||||
context:
|
||||
- name: targetContent
|
||||
variable:
|
||||
jmesPath: target.data.content
|
||||
patchStrategicMerge:
|
||||
data:
|
||||
content: "{{ triggerContent }}"
|
||||
targetContent: "{{ targetContent }}"
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: target
|
||||
data:
|
||||
content: trigger
|
||||
targetContent: target
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: target
|
||||
data:
|
||||
content: target
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: trigger
|
||||
data:
|
||||
content: trigger
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: resources.yaml
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- policy.yaml
|
||||
assert:
|
||||
- policy-assert.yaml
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
- file: trigger.yaml
|
|
@ -0,0 +1,4 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
assert:
|
||||
- resources-assert.yaml
|
|
@ -0,0 +1,18 @@
|
|||
## Description
|
||||
|
||||
This test creates three `ConfigMap`s:
|
||||
- one without labels
|
||||
- one with label `foo: bar`
|
||||
- one with label `foo: not_bar`
|
||||
|
||||
It then creates a `ClusterPolicy` with a mutate existing rule targeting the previously created `ConfigMap`s.
|
||||
|
||||
The policy rule uses preconditions on the trigger resource to match only `ConfigMap`s with the `trigger` name.
|
||||
The policy rule also uses preconditions on target resources to match only `ConfigMap`s with he label `foo: bar`.
|
||||
The policy mutates target resources passing preconditions by copying the `data.content` from the trigger `ConfigMap` to the target `ConfigMap`.
|
||||
|
||||
Finally, the test creates the trigger config map.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
Only the target config map with label `foo: bar` should have its content updated.
|
|
@ -0,0 +1,9 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: update-targets
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
|
@ -0,0 +1,31 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: update-targets
|
||||
spec:
|
||||
background: false
|
||||
rules:
|
||||
- name: update-targets
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- ConfigMap
|
||||
preconditions:
|
||||
all:
|
||||
- key: "{{ request.object.metadata.name }}"
|
||||
operator: Equals
|
||||
value: trigger
|
||||
mutate:
|
||||
targets:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
namespace: "{{ request.object.metadata.namespace }}"
|
||||
preconditions:
|
||||
all:
|
||||
- key: "{{ target.metadata.labels.foo || '' }}"
|
||||
operator: Equals
|
||||
value: bar
|
||||
patchStrategicMerge:
|
||||
data:
|
||||
content: "{{ request.object.data.content }}"
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: target-1
|
||||
data:
|
||||
content: trigger
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: target-2
|
||||
data:
|
||||
content: abc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: target-3
|
||||
data:
|
||||
content: abc
|
|
@ -0,0 +1,24 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: target-1
|
||||
labels:
|
||||
foo: bar
|
||||
data:
|
||||
content: abc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: target-2
|
||||
labels:
|
||||
foo: not_bar
|
||||
data:
|
||||
content: abc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: target-3
|
||||
data:
|
||||
content: abc
|
|
@ -0,0 +1,6 @@
|
|||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: trigger
|
||||
data:
|
||||
content: trigger
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: kuttl.dev/v1beta1
|
||||
kind: TestStep
|
||||
apply:
|
||||
# - file: policy-1.yaml
|
||||
# shouldFail: true
|
||||
- file: policy-2.yaml
|
||||
shouldFail: true
|
|
@ -0,0 +1,8 @@
|
|||
## Description
|
||||
|
||||
This test tries to create policies referencing `target` in the trigger preconditions or context of a mutate existing rule.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
Policies shoudl be rejected.
|
||||
Referencing `target` is only allowed in the target section of a mutate existing rule.
|
|
@ -0,0 +1,35 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: update-targets
|
||||
spec:
|
||||
background: false
|
||||
rules:
|
||||
- name: update-targets
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- ConfigMap
|
||||
context:
|
||||
- name: triggerContent
|
||||
variable:
|
||||
jmesPath: request.object.data.content
|
||||
- name: targetContent
|
||||
variable:
|
||||
jmesPath: target.data.content
|
||||
preconditions:
|
||||
all:
|
||||
- key: "{{ request.object.metadata.name }}"
|
||||
operator: Equals
|
||||
value: trigger
|
||||
mutate:
|
||||
targets:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
namespace: "{{ request.object.metadata.namespace }}"
|
||||
name: target*
|
||||
patchStrategicMerge:
|
||||
data:
|
||||
content: "{{ triggerContent }}"
|
||||
targetContent: "{{ targetContent }}"
|
|
@ -0,0 +1,39 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: update-targets
|
||||
spec:
|
||||
background: false
|
||||
rules:
|
||||
- name: update-targets
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- ConfigMap
|
||||
context:
|
||||
- name: triggerContent
|
||||
variable:
|
||||
jmesPath: request.object.data.content
|
||||
preconditions:
|
||||
all:
|
||||
- key: "{{ request.object.metadata.name }}"
|
||||
operator: Equals
|
||||
value: trigger
|
||||
- key: "{{ target.data.content }}"
|
||||
operator: Equals
|
||||
value: target
|
||||
mutate:
|
||||
targets:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
namespace: "{{ request.object.metadata.namespace }}"
|
||||
name: target*
|
||||
context:
|
||||
- name: targetContent
|
||||
variable:
|
||||
jmesPath: target.data.content
|
||||
patchStrategicMerge:
|
||||
data:
|
||||
content: "{{ triggerContent }}"
|
||||
targetContent: "{{ targetContent }}"
|
Loading…
Reference in a new issue