mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
fix: block generate policies when lack of permission to operate downstream resources (#6610)
* debug Signed-off-by: ShutingZhao <shuting@nirmata.com> * return on errors only Signed-off-by: ShutingZhao <shuting@nirmata.com> * update clusterrolebinding Signed-off-by: ShutingZhao <shuting@nirmata.com> * update clusterrolebinding Signed-off-by: ShutingZhao <shuting@nirmata.com> * remove debug Signed-off-by: ShutingZhao <shuting@nirmata.com> * add kuttl tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix ns Signed-off-by: ShutingZhao <shuting@nirmata.com> --------- Signed-off-by: ShutingZhao <shuting@nirmata.com>
This commit is contained in:
parent
f5e96e6ef2
commit
6249ab70e8
58 changed files with 587 additions and 64 deletions
|
@ -14,5 +14,8 @@ subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: {{ template "kyverno.background-controller.serviceAccountName" . }}
|
name: {{ template "kyverno.background-controller.serviceAccountName" . }}
|
||||||
namespace: {{ template "kyverno.namespace" . }}
|
namespace: {{ template "kyverno.namespace" . }}
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: {{ template "kyverno.admission-controller.serviceAccountName" . }}
|
||||||
|
namespace: {{ template "kyverno.namespace" . }}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package policy
|
package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||||
|
@ -14,7 +15,7 @@ import (
|
||||||
|
|
||||||
// Validation provides methods to validate a rule
|
// Validation provides methods to validate a rule
|
||||||
type Validation interface {
|
type Validation interface {
|
||||||
Validate() (string, error)
|
Validate(ctx context.Context) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateAction performs validation on the rule actions
|
// validateAction performs validation on the rule actions
|
||||||
|
@ -27,11 +28,10 @@ func validateActions(idx int, rule *kyvernov1.Rule, client dclient.Interface, mo
|
||||||
}
|
}
|
||||||
|
|
||||||
var checker Validation
|
var checker Validation
|
||||||
|
|
||||||
// Mutate
|
// Mutate
|
||||||
if rule.HasMutate() {
|
if rule.HasMutate() {
|
||||||
checker = mutate.NewMutateFactory(rule.Mutation)
|
checker = mutate.NewMutateFactory(rule.Mutation, client)
|
||||||
if path, err := checker.Validate(); err != nil {
|
if path, err := checker.Validate(context.TODO()); err != nil {
|
||||||
return fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", idx, path, err)
|
return fmt.Errorf("path: spec.rules[%d].mutate.%s.: %v", idx, path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ func validateActions(idx int, rule *kyvernov1.Rule, client dclient.Interface, mo
|
||||||
// Validate
|
// Validate
|
||||||
if rule.HasValidate() {
|
if rule.HasValidate() {
|
||||||
checker = validate.NewValidateFactory(&rule.Validation)
|
checker = validate.NewValidateFactory(&rule.Validation)
|
||||||
if path, err := checker.Validate(); err != nil {
|
if path, err := checker.Validate(context.TODO()); err != nil {
|
||||||
return fmt.Errorf("path: spec.rules[%d].validate.%s.: %v", idx, path, err)
|
return fmt.Errorf("path: spec.rules[%d].validate.%s.: %v", idx, path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,12 +51,12 @@ func validateActions(idx int, rule *kyvernov1.Rule, client dclient.Interface, mo
|
||||||
// this need to modified to use different implementation for online and offline mode
|
// this need to modified to use different implementation for online and offline mode
|
||||||
if mock {
|
if mock {
|
||||||
checker = generate.NewFakeGenerate(rule.Generation)
|
checker = generate.NewFakeGenerate(rule.Generation)
|
||||||
if path, err := checker.Validate(); err != nil {
|
if path, err := checker.Validate(context.TODO()); err != nil {
|
||||||
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
checker = generate.NewGenerateFactory(client, rule.Generation, logging.GlobalLogger())
|
checker = generate.NewGenerateFactory(client, rule.Generation, logging.GlobalLogger())
|
||||||
if path, err := checker.Validate(); err != nil {
|
if path, err := checker.Validate(context.TODO()); err != nil {
|
||||||
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
return fmt.Errorf("path: spec.rules[%d].generate.%s.: %v", idx, path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ func NewGenerateFactory(client dclient.Interface, rule kyvernov1.Generation, log
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the 'generate' rule
|
// Validate validates the 'generate' rule
|
||||||
func (g *Generate) Validate() (string, error) {
|
func (g *Generate) Validate(ctx context.Context) (string, error) {
|
||||||
rule := g.rule
|
rule := g.rule
|
||||||
if rule.GetData() != nil && rule.Clone != (kyvernov1.CloneFrom{}) {
|
if rule.GetData() != nil && rule.Clone != (kyvernov1.CloneFrom{}) {
|
||||||
return "", fmt.Errorf("only one of data or clone can be specified")
|
return "", fmt.Errorf("only one of data or clone can be specified")
|
||||||
|
@ -91,12 +91,12 @@ func (g *Generate) Validate() (string, error) {
|
||||||
if len(rule.CloneList.Kinds) != 0 {
|
if len(rule.CloneList.Kinds) != 0 {
|
||||||
for _, kind = range rule.CloneList.Kinds {
|
for _, kind = range rule.CloneList.Kinds {
|
||||||
_, kind = kubeutils.GetKindFromGVK(kind)
|
_, kind = kubeutils.GetKindFromGVK(kind)
|
||||||
if err := g.canIGenerate(kind, namespace); err != nil {
|
if err := g.canIGenerate(ctx, kind, namespace); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := g.canIGenerate(kind, namespace); err != nil {
|
if err := g.canIGenerate(ctx, kind, namespace); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func (g *Generate) validateClone(c kyvernov1.CloneFrom, cl kyvernov1.CloneList,
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("kyverno does not have permissions to 'get' resource %s/%s. Update permissions in ClusterRole 'kyverno:generate'", kind, namespace)
|
return "", fmt.Errorf("kyverno does not have permissions to 'get' resource %s/%s. Update permissions in ClusterRole 'kyverno:background-controller:additional'", kind, namespace)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.log.V(4).Info("name & namespace uses variables, so cannot be resolved. Skipping Auth Checks.")
|
g.log.V(4).Info("name & namespace uses variables, so cannot be resolved. Skipping Auth Checks.")
|
||||||
|
@ -128,46 +128,46 @@ func (g *Generate) validateClone(c kyvernov1.CloneFrom, cl kyvernov1.CloneList,
|
||||||
}
|
}
|
||||||
|
|
||||||
// canIGenerate returns a error if kyverno cannot perform operations
|
// canIGenerate returns a error if kyverno cannot perform operations
|
||||||
func (g *Generate) canIGenerate(kind, namespace string) error {
|
func (g *Generate) canIGenerate(ctx context.Context, kind, namespace string) error {
|
||||||
// Skip if there is variable defined
|
// Skip if there is variable defined
|
||||||
authCheck := g.authCheck
|
authCheck := g.authCheck
|
||||||
if !regex.IsVariable(kind) && !regex.IsVariable(namespace) {
|
if !regex.IsVariable(kind) && !regex.IsVariable(namespace) {
|
||||||
// CREATE
|
// CREATE
|
||||||
ok, err := authCheck.CanICreate(context.TODO(), kind, namespace)
|
ok, err := authCheck.CanICreate(ctx, kind, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// machinery error
|
// machinery error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("kyverno does not have permissions to 'create' resource %s/%s. Update permissions in ClusterRole 'kyverno:generate'", kind, namespace)
|
return fmt.Errorf("kyverno does not have permissions to 'create' resource %s/%s. Update permissions in ClusterRole 'kyverno:background-controller:additional'", kind, namespace)
|
||||||
}
|
}
|
||||||
// UPDATE
|
// UPDATE
|
||||||
ok, err = authCheck.CanIUpdate(context.TODO(), kind, namespace)
|
ok, err = authCheck.CanIUpdate(ctx, kind, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// machinery error
|
// machinery error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("kyverno does not have permissions to 'update' resource %s/%s. Update permissions in ClusterRole 'kyverno:generate'", kind, namespace)
|
return fmt.Errorf("kyverno does not have permissions to 'update' resource %s/%s. Update permissions in ClusterRole 'kyverno:background-controller:additional'", kind, namespace)
|
||||||
}
|
}
|
||||||
// GET
|
// GET
|
||||||
ok, err = authCheck.CanIGet(context.TODO(), kind, namespace)
|
ok, err = authCheck.CanIGet(ctx, kind, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// machinery error
|
// machinery error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("kyverno does not have permissions to 'get' resource %s/%s. Update permissions in ClusterRole 'kyverno:generate'", kind, namespace)
|
return fmt.Errorf("kyverno does not have permissions to 'get' resource %s/%s. Update permissions in ClusterRole 'kyverno:background-controller:additional'", kind, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE
|
// DELETE
|
||||||
ok, err = authCheck.CanIDelete(context.TODO(), kind, namespace)
|
ok, err = authCheck.CanIDelete(ctx, kind, namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// machinery error
|
// machinery error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("kyverno does not have permissions to 'delete' resource %s/%s. Update permissions in ClusterRole 'kyverno:generate'", kind, namespace)
|
return fmt.Errorf("kyverno does not have permissions to 'delete' resource %s/%s. Update permissions in ClusterRole 'kyverno:background-controller:additional'", kind, namespace)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g.log.V(4).Info("name & namespace uses variables, so cannot be resolved. Skipping Auth Checks.")
|
g.log.V(4).Info("name & namespace uses variables, so cannot be resolved. Skipping Auth Checks.")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package generate
|
package generate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ func Test_Validate_Generate(t *testing.T) {
|
||||||
err := json.Unmarshal(rawGenerate, &genRule)
|
err := json.Unmarshal(rawGenerate, &genRule)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewFakeGenerate(genRule)
|
checker := NewFakeGenerate(genRule)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +67,7 @@ func Test_Validate_Generate_HasAnchors(t *testing.T) {
|
||||||
err = json.Unmarshal(rawGenerate, &genRule)
|
err = json.Unmarshal(rawGenerate, &genRule)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewFakeGenerate(genRule)
|
checker := NewFakeGenerate(genRule)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +84,7 @@ func Test_Validate_Generate_HasAnchors(t *testing.T) {
|
||||||
err = json.Unmarshal(rawGenerate, &genRule)
|
err = json.Unmarshal(rawGenerate, &genRule)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker = NewFakeGenerate(genRule)
|
checker = NewFakeGenerate(genRule)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
37
pkg/policy/mutate/auth.go
Normal file
37
pkg/policy/mutate/auth.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package mutate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/kyverno/kyverno/pkg/auth"
|
||||||
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||||
|
)
|
||||||
|
|
||||||
|
type authChecker struct {
|
||||||
|
client dclient.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthChecker interface {
|
||||||
|
CanICreate(ctx context.Context, kind, namespace, subresource string) (bool, error)
|
||||||
|
CanIUpdate(ctx context.Context, kind, namespace, subresource string) (bool, error)
|
||||||
|
CanIGet(ctx context.Context, kind, namespace, subresource string) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAuthChecker(client dclient.Interface) AuthChecker {
|
||||||
|
return &authChecker{client: client}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *authChecker) CanICreate(ctx context.Context, kind, namespace, subresource string) (bool, error) {
|
||||||
|
checker := auth.NewCanI(a.client.Discovery(), a.client.GetKubeClient().AuthorizationV1().SelfSubjectAccessReviews(), kind, namespace, "create", subresource)
|
||||||
|
return checker.RunAccessCheck(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *authChecker) CanIUpdate(ctx context.Context, kind, namespace, subresource string) (bool, error) {
|
||||||
|
checker := auth.NewCanI(a.client.Discovery(), a.client.GetKubeClient().AuthorizationV1().SelfSubjectAccessReviews(), kind, namespace, "update", subresource)
|
||||||
|
return checker.RunAccessCheck(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *authChecker) CanIGet(ctx context.Context, kind, namespace, subresource string) (bool, error) {
|
||||||
|
checker := auth.NewCanI(a.client.Discovery(), a.client.GetKubeClient().AuthorizationV1().SelfSubjectAccessReviews(), kind, namespace, "get", subresource)
|
||||||
|
return checker.RunAccessCheck(ctx)
|
||||||
|
}
|
|
@ -1,27 +1,34 @@
|
||||||
package mutate
|
package mutate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||||
|
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||||
|
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
|
||||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||||
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||||
|
"go.uber.org/multierr"
|
||||||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mutate provides implementation to validate 'mutate' rule
|
// Mutate provides implementation to validate 'mutate' rule
|
||||||
type Mutate struct {
|
type Mutate struct {
|
||||||
mutation kyvernov1.Mutation
|
mutation kyvernov1.Mutation
|
||||||
|
authChecker AuthChecker
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMutateFactory returns a new instance of Mutate validation checker
|
// NewMutateFactory returns a new instance of Mutate validation checker
|
||||||
func NewMutateFactory(m kyvernov1.Mutation) *Mutate {
|
func NewMutateFactory(m kyvernov1.Mutation, client dclient.Interface) *Mutate {
|
||||||
return &Mutate{
|
return &Mutate{
|
||||||
mutation: m,
|
mutation: m,
|
||||||
|
authChecker: newAuthChecker(client),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the 'mutate' rule
|
// Validate validates the 'mutate' rule
|
||||||
func (m *Mutate) Validate() (string, error) {
|
func (m *Mutate) Validate(ctx context.Context) (string, error) {
|
||||||
if m.hasForEach() {
|
if m.hasForEach() {
|
||||||
if m.hasPatchStrategicMerge() || m.hasPatchesJSON6902() {
|
if m.hasPatchStrategicMerge() || m.hasPatchesJSON6902() {
|
||||||
return "foreach", fmt.Errorf("only one of `foreach`, `patchStrategicMerge`, or `patchesJson6902` is allowed")
|
return "foreach", fmt.Errorf("only one of `foreach`, `patchStrategicMerge`, or `patchesJson6902` is allowed")
|
||||||
|
@ -34,6 +41,11 @@ func (m *Mutate) Validate() (string, error) {
|
||||||
return "foreach", fmt.Errorf("only one of `patchStrategicMerge` or `patchesJson6902` is allowed")
|
return "foreach", fmt.Errorf("only one of `patchStrategicMerge` or `patchesJson6902` is allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.mutation.Targets != nil {
|
||||||
|
if err := m.validateAuth(ctx, m.mutation.Targets); err != nil {
|
||||||
|
return "targets", fmt.Errorf("auth check fails, require additional privileges, update the ClusterRole 'kyverno:background-controller:additional':%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,3 +89,30 @@ func (m *Mutate) hasPatchStrategicMerge() bool {
|
||||||
func (m *Mutate) hasPatchesJSON6902() bool {
|
func (m *Mutate) hasPatchesJSON6902() bool {
|
||||||
return m.mutation.PatchesJSON6902 != ""
|
return m.mutation.PatchesJSON6902 != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Mutate) validateAuth(ctx context.Context, targets []kyvernov1.ResourceSpec) error {
|
||||||
|
var errs []error
|
||||||
|
for _, target := range targets {
|
||||||
|
if !regex.IsVariable(target.Namespace) {
|
||||||
|
_, _, k, sub := kubeutils.ParseKindSelector(target.Kind)
|
||||||
|
if ok, err := m.authChecker.CanICreate(ctx, k, target.Namespace, sub); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
} else if !ok {
|
||||||
|
errs = append(errs, fmt.Errorf("cannot %s %s/%s in namespace %s", "create", k, sub, target.Namespace))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok, err := m.authChecker.CanIUpdate(ctx, k, target.Namespace, sub); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
} else if !ok {
|
||||||
|
errs = append(errs, fmt.Errorf("cannot %s %s/%s in namespace %s", "update", k, sub, target.Namespace))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok, err := m.authChecker.CanIGet(ctx, k, target.Namespace, sub); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
} else if !ok {
|
||||||
|
errs = append(errs, fmt.Errorf("cannot %s %s/%s in namespace %s", "get", k, sub, target.Namespace))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return multierr.Combine(errs...)
|
||||||
|
}
|
||||||
|
|
|
@ -252,7 +252,9 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
|
||||||
// validate Cluster Resources in namespaced policy
|
// validate Cluster Resources in namespaced policy
|
||||||
// For namespaced policy, ClusterResource type field and values are not allowed in match and exclude
|
// For namespaced policy, ClusterResource type field and values are not allowed in match and exclude
|
||||||
if namespaced {
|
if namespaced {
|
||||||
return warnings, checkClusterResourceInMatchAndExclude(rule, clusterResources, policy.GetNamespace(), mock, res)
|
if err := checkClusterResourceInMatchAndExclude(rule, clusterResources, policy.GetNamespace(), mock, res); err != nil {
|
||||||
|
return warnings, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validateActions(i, &rules[i], client, mock); err != nil {
|
if err := validateActions(i, &rules[i], client, mock); err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||||
|
@ -24,7 +25,7 @@ func NewValidateFactory(rule *kyvernov1.Validation) *Validate {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the 'validate' rule
|
// Validate validates the 'validate' rule
|
||||||
func (v *Validate) Validate() (string, error) {
|
func (v *Validate) Validate(ctx context.Context) (string, error) {
|
||||||
if err := v.validateElements(); err != nil {
|
if err := v.validateElements(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ func Test_Validate_OverlayPattern_Empty(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
checker := NewValidateFactory(&validation)
|
checker := NewValidateFactory(&validation)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +32,7 @@ func Test_Validate_OverlayPattern_Nil_PatternAnypattern(t *testing.T) {
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewValidateFactory(&validation)
|
checker := NewValidateFactory(&validation)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +70,7 @@ func Test_Validate_OverlayPattern_Exist_PatternAnypattern(t *testing.T) {
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewValidateFactory(&validation)
|
checker := NewValidateFactory(&validation)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +108,7 @@ func Test_Validate_OverlayPattern_Valid(t *testing.T) {
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewValidateFactory(&validation)
|
checker := NewValidateFactory(&validation)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +141,7 @@ func Test_Validate_ExistingAnchor_AnchorOnMap(t *testing.T) {
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewValidateFactory(&validation)
|
checker := NewValidateFactory(&validation)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +171,7 @@ func Test_Validate_ExistingAnchor_AnchorOnString(t *testing.T) {
|
||||||
err := json.Unmarshal(rawValidation, &validation)
|
err := json.Unmarshal(rawValidation, &validation)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewValidateFactory(&validation)
|
checker := NewValidateFactory(&validation)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +204,7 @@ func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValidation, &validation)
|
err = json.Unmarshal(rawValidation, &validation)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewValidateFactory(&validation)
|
checker := NewValidateFactory(&validation)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
rawValidation = []byte(`
|
rawValidation = []byte(`
|
||||||
|
@ -228,7 +229,7 @@ func Test_Validate_ExistingAnchor_Valid(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValidation, &validation)
|
err = json.Unmarshal(rawValidation, &validation)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker = NewValidateFactory(&validation)
|
checker = NewValidateFactory(&validation)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +270,7 @@ func Test_Validate_Validate_ValidAnchor(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
checker := NewValidateFactory(&validate)
|
checker := NewValidateFactory(&validate)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +292,7 @@ func Test_Validate_Validate_ValidAnchor(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
checker = NewValidateFactory(&validate)
|
checker = NewValidateFactory(&validate)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +319,7 @@ func Test_Validate_Validate_Mismatched(t *testing.T) {
|
||||||
err := json.Unmarshal(rawValidate, &validate)
|
err := json.Unmarshal(rawValidate, &validate)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewValidateFactory(&validate)
|
checker := NewValidateFactory(&validate)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,7 +349,7 @@ func Test_Validate_Validate_Unsupported(t *testing.T) {
|
||||||
err = json.Unmarshal(rawValidate, &validate)
|
err = json.Unmarshal(rawValidate, &validate)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
checker := NewValidateFactory(&validate)
|
checker := NewValidateFactory(&validate)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +375,7 @@ func Test_Validate_Validate_Unsupported(t *testing.T) {
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
|
||||||
checker = NewValidateFactory(&validate)
|
checker = NewValidateFactory(&validate)
|
||||||
if _, err := checker.Validate(); err != nil {
|
if _, err := checker.Validate(context.TODO()); err != nil {
|
||||||
assert.Assert(t, err != nil)
|
assert.Assert(t, err != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,10 @@ spec:
|
||||||
example.com/sm-sync: "true"
|
example.com/sm-sync: "true"
|
||||||
generate:
|
generate:
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: ConfigMap
|
||||||
name: "{{request.object.metadata.name}}-modify"
|
name: "{{request.object.metadata.name}}-modify"
|
||||||
namespace: match-trigger-namespace-ns
|
namespace: match-trigger-namespace-ns
|
||||||
synchronize: true
|
synchronize: true
|
||||||
data:
|
data:
|
||||||
type: Opaque
|
|
||||||
data:
|
data:
|
||||||
modify: Zm9v
|
modify: Zm9v
|
|
@ -1,8 +1,7 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
modify: Zm9v
|
modify: Zm9v
|
||||||
kind: Secret
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: regcred-modify
|
name: regcred-modify
|
||||||
namespace: match-trigger-namespace-ns
|
namespace: match-trigger-namespace-ns
|
||||||
type: Opaque
|
|
|
@ -37,11 +37,10 @@ spec:
|
||||||
example.com/sm-sync: "true"
|
example.com/sm-sync: "true"
|
||||||
generate:
|
generate:
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: ConfigMap
|
||||||
name: "{{request.object.metadata.name}}-modify"
|
name: "{{request.object.metadata.name}}-modify"
|
||||||
namespace: non-match-trigger-namespace-ns
|
namespace: non-match-trigger-namespace-ns
|
||||||
synchronize: true
|
synchronize: true
|
||||||
data:
|
data:
|
||||||
type: Opaque
|
|
||||||
data:
|
data:
|
||||||
modify: Zm9v
|
modify: Zm9v
|
|
@ -1,8 +1,7 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
modify: Zm9v
|
modify: Zm9v
|
||||||
kind: Secret
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: regcred-modify
|
name: regcred-modify
|
||||||
namespace: non-match-trigger-namespace-ns
|
namespace: non-match-trigger-namespace-ns
|
||||||
type: Opaque
|
|
|
@ -3,7 +3,7 @@ kind: ClusterPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -3,7 +3,7 @@ kind: ClusterPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -3,7 +3,7 @@ kind: ClusterPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -3,7 +3,7 @@ kind: ClusterPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -3,7 +3,7 @@ kind: ClusterPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: i-changed-this
|
- name: i-changed-this
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -3,7 +3,7 @@ kind: ClusterPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- file: policy.yaml
|
||||||
|
shouldFail: true
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- serviceaccounts
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- policy.yaml
|
||||||
|
assert:
|
||||||
|
- policy-assert.yaml
|
|
@ -0,0 +1,27 @@
|
||||||
|
## reset changed clusterrole for the rest of the tests
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
- networkpolicies
|
||||||
|
- resourcequotas
|
||||||
|
- secrets
|
||||||
|
- roles
|
||||||
|
- rolebindings
|
||||||
|
- limitranges
|
||||||
|
- namespaces
|
||||||
|
- nodes
|
||||||
|
- nodes/status
|
||||||
|
- pods
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,12 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test ensures that a generate policy is denied when it does not have corresponding permissions to generate the downstream resource.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
The test fails if the policy creation is allowed, otherwise passes.
|
||||||
|
|
||||||
|
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
https://github.com/kyverno/kyverno/issues/6584
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: cpol-validate-create-sa-permission
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
|
@ -0,0 +1,21 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: cpol-validate-create-sa-permission
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- name: clone-secret
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- ConfigMap
|
||||||
|
generate:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
name: cpol-validate-create-sa-permission-sa
|
||||||
|
namespace: default
|
||||||
|
synchronize: true
|
||||||
|
clone:
|
||||||
|
namespace: default
|
||||||
|
name: regcred
|
|
@ -4,7 +4,7 @@ metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -4,7 +4,7 @@ metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -4,7 +4,7 @@ metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -4,7 +4,7 @@ metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -4,7 +4,7 @@ metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: i-changed-this
|
- name: i-changed-this
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -4,7 +4,7 @@ metadata:
|
||||||
name: generate-update-rule-spec
|
name: generate-update-rule-spec
|
||||||
namespace: default
|
namespace: default
|
||||||
spec:
|
spec:
|
||||||
generateExistingOnPolicyUpdate: false
|
generateExisting: false
|
||||||
rules:
|
rules:
|
||||||
- name: k-kafka-address
|
- name: k-kafka-address
|
||||||
match:
|
match:
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: pol-validate-create-sa-permission-ns
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- file: policy.yaml
|
||||||
|
shouldFail: true
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- serviceaccounts
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- policy.yaml
|
||||||
|
assert:
|
||||||
|
- policy-assert.yaml
|
|
@ -0,0 +1,27 @@
|
||||||
|
## reset changed clusterrole for the rest of the tests
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
- networkpolicies
|
||||||
|
- resourcequotas
|
||||||
|
- secrets
|
||||||
|
- roles
|
||||||
|
- rolebindings
|
||||||
|
- limitranges
|
||||||
|
- namespaces
|
||||||
|
- nodes
|
||||||
|
- nodes/status
|
||||||
|
- pods
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,12 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test ensures that a generate policy is denied when it does not have corresponding permissions to generate the downstream resource.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
The test fails if the policy creation is allowed, otherwise passes.
|
||||||
|
|
||||||
|
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
https://github.com/kyverno/kyverno/issues/6584
|
|
@ -0,0 +1,10 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: Policy
|
||||||
|
metadata:
|
||||||
|
name: pol-validate-create-sa-permission
|
||||||
|
namespace: pol-validate-create-sa-permission-ns
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
|
@ -0,0 +1,22 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: Policy
|
||||||
|
metadata:
|
||||||
|
name: pol-validate-create-sa-permission
|
||||||
|
namespace: pol-validate-create-sa-permission-ns
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- name: clone-secret
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- ConfigMap
|
||||||
|
generate:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
name: cpol-validate-create-sa-permission-sa
|
||||||
|
namespace: pol-validate-create-sa-permission-ns
|
||||||
|
synchronize: true
|
||||||
|
clone:
|
||||||
|
namespace: pol-validate-create-sa-permission-ns
|
||||||
|
name: regcred
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- file: policy.yaml
|
||||||
|
shouldFail: true
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- serviceaccounts
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- policy.yaml
|
||||||
|
assert:
|
||||||
|
- policy-assert.yaml
|
|
@ -0,0 +1,27 @@
|
||||||
|
## reset changed clusterrole for the rest of the tests
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
- networkpolicies
|
||||||
|
- resourcequotas
|
||||||
|
- secrets
|
||||||
|
- roles
|
||||||
|
- rolebindings
|
||||||
|
- limitranges
|
||||||
|
- namespaces
|
||||||
|
- nodes
|
||||||
|
- nodes/status
|
||||||
|
- pods
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,12 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test ensures that a mutate existing policy is denied when it does not have corresponding permissions to generate the downstream resource.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
The test fails if the policy creation is allowed, otherwise passes.
|
||||||
|
|
||||||
|
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
https://github.com/kyverno/kyverno/issues/6584
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: cpol-mutate-existing-auth-check
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
|
@ -0,0 +1,22 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: cpol-mutate-existing-auth-check
|
||||||
|
spec:
|
||||||
|
mutateExistingOnPolicyUpdate: true
|
||||||
|
background: false
|
||||||
|
rules:
|
||||||
|
- name: label-privileged-namespaces
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- Namespace
|
||||||
|
mutate:
|
||||||
|
targets:
|
||||||
|
- apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
patchStrategicMerge:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
foo: bar
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: pol-mutate-existing-auth-check-ns
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- file: policy.yaml
|
||||||
|
shouldFail: true
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- serviceaccounts
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,6 @@
|
||||||
|
apiVersion: kuttl.dev/v1beta1
|
||||||
|
kind: TestStep
|
||||||
|
apply:
|
||||||
|
- policy.yaml
|
||||||
|
assert:
|
||||||
|
- policy-assert.yaml
|
|
@ -0,0 +1,27 @@
|
||||||
|
## reset changed clusterrole for the rest of the tests
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
- networkpolicies
|
||||||
|
- resourcequotas
|
||||||
|
- secrets
|
||||||
|
- roles
|
||||||
|
- rolebindings
|
||||||
|
- limitranges
|
||||||
|
- namespaces
|
||||||
|
- nodes
|
||||||
|
- nodes/status
|
||||||
|
- pods
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,12 @@
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This test ensures that a mutate existing policy is denied when it does not have corresponding permissions to generate the downstream resource.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
The test fails if the policy creation is allowed, otherwise passes.
|
||||||
|
|
||||||
|
|
||||||
|
## Reference Issue(s)
|
||||||
|
|
||||||
|
https://github.com/kyverno/kyverno/issues/6584
|
|
@ -0,0 +1,10 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: Policy
|
||||||
|
metadata:
|
||||||
|
name: pol-mutate-existing-auth-check
|
||||||
|
namespace: pol-mutate-existing-auth-check-ns
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
|
@ -0,0 +1,24 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: Policy
|
||||||
|
metadata:
|
||||||
|
name: pol-mutate-existing-auth-check
|
||||||
|
namespace: pol-mutate-existing-auth-check-ns
|
||||||
|
spec:
|
||||||
|
mutateExistingOnPolicyUpdate: true
|
||||||
|
background: false
|
||||||
|
rules:
|
||||||
|
- name: label-privileged-namespaces
|
||||||
|
match:
|
||||||
|
any:
|
||||||
|
- resources:
|
||||||
|
kinds:
|
||||||
|
- ConfigMap
|
||||||
|
mutate:
|
||||||
|
targets:
|
||||||
|
- apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
namespace: pol-mutate-existing-auth-check-ns
|
||||||
|
patchStrategicMerge:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
foo: bar
|
|
@ -0,0 +1,16 @@
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- deployments
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
|
@ -0,0 +1,28 @@
|
||||||
|
## reset changed clusterrole for the rest of the tests
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: kyverno:background-controller:additional
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- '*'
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
- networkpolicies
|
||||||
|
- resourcequotas
|
||||||
|
- secrets
|
||||||
|
- roles
|
||||||
|
- rolebindings
|
||||||
|
- limitranges
|
||||||
|
- namespaces
|
||||||
|
- nodes
|
||||||
|
- nodes/status
|
||||||
|
- pods
|
||||||
|
- deployments
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
Loading…
Reference in a new issue