2020-03-11 18:14:23 -07:00
|
|
|
package mutate
|
|
|
|
|
|
|
|
import (
|
2023-03-22 21:14:57 +08:00
|
|
|
"context"
|
2020-03-11 18:14:23 -07:00
|
|
|
"fmt"
|
2023-06-22 22:14:06 +08:00
|
|
|
"strings"
|
2020-03-11 18:14:23 -07:00
|
|
|
|
2022-05-17 13:12:43 +02:00
|
|
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
2024-08-20 01:55:32 -07:00
|
|
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
2023-03-22 21:14:57 +08:00
|
|
|
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
|
2024-08-20 01:55:32 -07:00
|
|
|
"github.com/kyverno/kyverno/pkg/logging"
|
2024-01-24 10:37:48 +01:00
|
|
|
"github.com/kyverno/kyverno/pkg/policy/auth"
|
2024-08-20 01:55:32 -07:00
|
|
|
"github.com/kyverno/kyverno/pkg/policy/auth/fake"
|
2023-03-22 21:14:57 +08:00
|
|
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
|
|
|
"go.uber.org/multierr"
|
2020-03-11 18:14:23 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
// Mutate provides implementation to validate 'mutate' rule
|
|
|
|
type Mutate struct {
|
2023-03-22 21:14:57 +08:00
|
|
|
mutation kyvernov1.Mutation
|
2024-08-20 01:55:32 -07:00
|
|
|
authChecker auth.AuthChecks
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
|
|
|
|
2022-05-17 08:19:03 +02:00
|
|
|
// NewMutateFactory returns a new instance of Mutate validation checker
|
2024-08-20 01:55:32 -07:00
|
|
|
func NewMutateFactory(m kyvernov1.Mutation, client dclient.Interface, mock bool, backgroundSA string) *Mutate {
|
|
|
|
var authCheck auth.AuthChecks
|
|
|
|
if mock {
|
|
|
|
authCheck = fake.NewFakeAuth()
|
|
|
|
} else {
|
|
|
|
authCheck = auth.NewAuth(client, backgroundSA, logging.GlobalLogger())
|
|
|
|
}
|
|
|
|
|
2022-01-04 17:36:33 -08:00
|
|
|
return &Mutate{
|
2023-03-22 21:14:57 +08:00
|
|
|
mutation: m,
|
2024-08-20 01:55:32 -07:00
|
|
|
authChecker: authCheck,
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-17 08:19:03 +02:00
|
|
|
// Validate validates the 'mutate' rule
|
2024-09-04 19:26:24 +08:00
|
|
|
func (m *Mutate) Validate(ctx context.Context, _ []string) (warnings []string, path string, err error) {
|
2022-01-04 17:36:33 -08:00
|
|
|
if m.hasForEach() {
|
2022-12-12 07:20:20 -08:00
|
|
|
if m.hasPatchStrategicMerge() || m.hasPatchesJSON6902() {
|
2024-08-20 01:55:32 -07:00
|
|
|
return nil, "foreach", fmt.Errorf("only one of `foreach`, `patchStrategicMerge`, or `patchesJson6902` is allowed")
|
2022-12-12 07:20:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return m.validateForEach("", m.mutation.ForEachMutation)
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
2022-01-04 17:36:33 -08:00
|
|
|
|
|
|
|
if m.hasPatchesJSON6902() && m.hasPatchStrategicMerge() {
|
2024-08-20 01:55:32 -07:00
|
|
|
return nil, "foreach", fmt.Errorf("only one of `patchStrategicMerge` or `patchesJson6902` is allowed")
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
2022-01-04 17:36:33 -08:00
|
|
|
|
2023-03-22 21:14:57 +08:00
|
|
|
if m.mutation.Targets != nil {
|
|
|
|
if err := m.validateAuth(ctx, m.mutation.Targets); err != nil {
|
2024-08-20 01:55:32 -07:00
|
|
|
return nil, "targets", fmt.Errorf("auth check fails, additional privileges are required for the service account '%s': %v", m.authChecker.User(), err)
|
2023-03-22 21:14:57 +08:00
|
|
|
}
|
|
|
|
}
|
2024-08-20 01:55:32 -07:00
|
|
|
return nil, "", nil
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
|
|
|
|
2024-08-20 01:55:32 -07:00
|
|
|
func (m *Mutate) validateForEach(tag string, foreach []kyvernov1.ForEachMutation) (warnings []string, path string, err error) {
|
2022-12-12 07:20:20 -08:00
|
|
|
for i, fe := range foreach {
|
|
|
|
tag = tag + fmt.Sprintf("foreach[%d]", i)
|
2024-07-30 13:52:41 +03:00
|
|
|
fem := fe.GetForEachMutation()
|
|
|
|
if len(fem) > 0 {
|
2024-08-20 01:55:32 -07:00
|
|
|
if fe.Context != nil || fe.AnyAllConditions != nil || fe.PatchesJSON6902 != "" || fe.RawPatchStrategicMerge != nil {
|
|
|
|
return nil, tag, fmt.Errorf("a nested foreach cannot contain other declarations")
|
2022-12-12 07:20:20 -08:00
|
|
|
}
|
|
|
|
|
2024-07-30 13:52:41 +03:00
|
|
|
return m.validateNestedForEach(tag, fem)
|
2022-12-12 07:20:20 -08:00
|
|
|
}
|
2020-03-11 18:14:23 -07:00
|
|
|
|
2022-03-06 20:07:51 +01:00
|
|
|
psm := fe.GetPatchStrategicMerge()
|
|
|
|
if (fe.PatchesJSON6902 == "" && psm == nil) || (fe.PatchesJSON6902 != "" && psm != nil) {
|
2024-08-20 01:55:32 -07:00
|
|
|
return nil, tag, fmt.Errorf("only one of `patchStrategicMerge` or `patchesJson6902` is allowed")
|
2022-01-04 17:36:33 -08:00
|
|
|
}
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
|
|
|
|
2024-08-20 01:55:32 -07:00
|
|
|
return nil, "", nil
|
2022-01-04 17:36:33 -08:00
|
|
|
}
|
|
|
|
|
2024-08-20 01:55:32 -07:00
|
|
|
func (m *Mutate) validateNestedForEach(tag string, j []kyvernov1.ForEachMutation) (warnings []string, path string, err error) {
|
2024-07-30 13:52:41 +03:00
|
|
|
if j != nil {
|
|
|
|
return m.validateForEach(tag, j)
|
2022-12-12 07:20:20 -08:00
|
|
|
}
|
|
|
|
|
2024-08-20 01:55:32 -07:00
|
|
|
return nil, "", nil
|
2022-12-12 07:20:20 -08:00
|
|
|
}
|
|
|
|
|
2022-01-04 17:36:33 -08:00
|
|
|
func (m *Mutate) hasForEach() bool {
|
|
|
|
return len(m.mutation.ForEachMutation) > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mutate) hasPatchStrategicMerge() bool {
|
2022-03-06 20:07:51 +01:00
|
|
|
return m.mutation.GetPatchStrategicMerge() != nil
|
2022-01-04 17:36:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mutate) hasPatchesJSON6902() bool {
|
|
|
|
return m.mutation.PatchesJSON6902 != ""
|
2020-03-11 18:14:23 -07:00
|
|
|
}
|
2023-03-22 21:14:57 +08:00
|
|
|
|
2023-04-03 21:58:58 +02:00
|
|
|
func (m *Mutate) validateAuth(ctx context.Context, targets []kyvernov1.TargetResourceSpec) error {
|
2023-03-22 21:14:57 +08:00
|
|
|
var errs []error
|
|
|
|
for _, target := range targets {
|
2024-08-20 01:55:32 -07:00
|
|
|
if regex.IsVariable(target.Kind) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
_, _, k, sub := kubeutils.ParseKindSelector(target.Kind)
|
|
|
|
gvk := strings.Join([]string{target.APIVersion, k}, "/")
|
|
|
|
verbs := []string{"get", "update"}
|
|
|
|
ok, msg, err := m.authChecker.CanI(ctx, verbs, gvk, target.Namespace, target.Name, sub)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !ok {
|
2024-08-28 19:09:58 +02:00
|
|
|
errs = append(errs, fmt.Errorf(msg)) //nolint:all
|
2023-03-22 21:14:57 +08:00
|
|
|
}
|
|
|
|
}
|
2024-08-20 01:55:32 -07:00
|
|
|
|
2023-03-22 21:14:57 +08:00
|
|
|
return multierr.Combine(errs...)
|
|
|
|
}
|