diff --git a/api/kyverno/v1/common_types.go b/api/kyverno/v1/common_types.go index e7f177feba..c74e9535ab 100644 --- a/api/kyverno/v1/common_types.go +++ b/api/kyverno/v1/common_types.go @@ -620,9 +620,15 @@ type CloneList struct { Selector *metav1.LabelSelector `json:"selector,omitempty" yaml:"selector,omitempty"` } -func (g *Generation) Validate(path *field.Path, clusterResources sets.Set[string]) (errs field.ErrorList) { - if err := g.validateTargetsScope(clusterResources); err != nil { - errs = append(errs, field.Forbidden(path.Child("generate").Child("namespace"), fmt.Sprintf("target resource scope mismatched: %v ", err))) +func (g *Generation) Validate(path *field.Path, namespaced bool, policyNamespace string, clusterResources sets.Set[string]) (errs field.ErrorList) { + if namespaced { + if err := g.validateTargetsScope(clusterResources, policyNamespace); err != nil { + errs = append(errs, field.Forbidden(path.Child("generate").Child("namespace"), fmt.Sprintf("target resource scope mismatched: %v ", err))) + } + } else { + if g.GetNamespace() == "" && g.CloneList.Namespace == "" { + errs = append(errs, field.Forbidden(path.Child("generate"), "target namespace must be set in a clusterpolicy")) + } } generateType, _ := g.GetTypeAndSync() @@ -662,15 +668,28 @@ func (g *Generation) SetData(in apiextensions.JSON) { g.RawData = ToJSON(in) } -func (g *Generation) validateTargetsScope(clusterResources sets.Set[string]) error { +func (g *Generation) validateTargetsScope(clusterResources sets.Set[string], policyNamespace string) error { target := g.ResourceSpec - if clusterResources.Has(target.GetKind()) { - if target.GetNamespace() != "" { - return fmt.Errorf("the target namespace must not be set for cluster-wide resource: %v", target.GetKind()) + if clusterResources.Has(target.GetAPIVersion() + "/" + target.GetKind()) { + return fmt.Errorf("the target must be a namespaced resource: %v/%v", target.GetAPIVersion(), target.GetKind()) + } + + if g.GetNamespace() != policyNamespace { + return fmt.Errorf("a namespaced policy cannot generate resources in other namespaces, expected: %v, received: %v", policyNamespace, g.GetNamespace()) + } + + if g.Clone.Name != "" { + if g.Clone.Namespace != policyNamespace { + return fmt.Errorf("a namespaced policy cannot clone resources from other namespaces, expected: %v, received: %v", policyNamespace, g.Clone.Namespace) } - } else { - if target.GetNamespace() == "" { - return fmt.Errorf("the target namespace must be set for namespaced resource: %v", target.GetKind()) + } + + for _, kind := range g.CloneList.Kinds { + if clusterResources.Has(kind) { + return fmt.Errorf("the source in cloneList must be a namespaced resource: %v/%v", target.GetAPIVersion(), target.GetKind()) + } + if g.CloneList.Namespace != policyNamespace { + return fmt.Errorf("a namespaced policy cannot clone resources from other namespace, expected: %v, received: %v", policyNamespace, g.CloneList.Namespace) } } diff --git a/api/kyverno/v1/rule_test.go b/api/kyverno/v1/rule_test.go index b5ec8d475e..f90271a0cb 100644 --- a/api/kyverno/v1/rule_test.go +++ b/api/kyverno/v1/rule_test.go @@ -1133,7 +1133,7 @@ func Test_Validate_ClusterPolicy_Generate_Variables(t *testing.T) { var rule *Rule err := json.Unmarshal(testcase.rule, &rule) assert.NilError(t, err, testcase.name) - errs := rule.ValidateGenerate(path, nil) + errs := rule.ValidateGenerate(path, false, "", nil) assert.Equal(t, len(errs) != 0, testcase.shouldFail, testcase.name) } } diff --git a/api/kyverno/v1/rule_types.go b/api/kyverno/v1/rule_types.go index 6ba9c4240f..31ed70a04e 100644 --- a/api/kyverno/v1/rule_types.go +++ b/api/kyverno/v1/rule_types.go @@ -404,12 +404,12 @@ func (r *Rule) ValidatePSaControlNames(path *field.Path) (errs field.ErrorList) return errs } -func (r *Rule) ValidateGenerate(path *field.Path, clusterResources sets.Set[string]) (errs field.ErrorList) { +func (r *Rule) ValidateGenerate(path *field.Path, namespaced bool, policyNamespace string, clusterResources sets.Set[string]) (errs field.ErrorList) { if !r.HasGenerate() { return nil } - return r.Generation.Validate(path, clusterResources) + return r.Generation.Validate(path, namespaced, policyNamespace, clusterResources) } // Validate implements programmatic validation @@ -420,6 +420,6 @@ func (r *Rule) Validate(path *field.Path, namespaced bool, policyNamespace strin errs = append(errs, r.ExcludeResources.Validate(path.Child("exclude"), namespaced, clusterResources)...) errs = append(errs, r.ValidateMutationRuleTargetNamespace(path, namespaced, policyNamespace)...) errs = append(errs, r.ValidatePSaControlNames(path)...) - errs = append(errs, r.ValidateGenerate(path, clusterResources)...) + errs = append(errs, r.ValidateGenerate(path, namespaced, policyNamespace, clusterResources)...) return errs } diff --git a/api/kyverno/v2beta1/clusterpolicy_types.go b/api/kyverno/v2beta1/clusterpolicy_types.go index d2642f22f6..739e5a3f67 100644 --- a/api/kyverno/v2beta1/clusterpolicy_types.go +++ b/api/kyverno/v2beta1/clusterpolicy_types.go @@ -105,7 +105,7 @@ func (p *ClusterPolicy) IsReady() bool { func (p *ClusterPolicy) Validate(clusterResources sets.Set[string]) (errs field.ErrorList) { errs = append(errs, kyvernov1.ValidateAutogenAnnotation(field.NewPath("metadata").Child("annotations"), p.GetAnnotations())...) errs = append(errs, kyvernov1.ValidatePolicyName(field.NewPath("name"), p.Name)...) - errs = append(errs, p.Spec.Validate(field.NewPath("spec"), p.IsNamespaced(), clusterResources)...) + errs = append(errs, p.Spec.Validate(field.NewPath("spec"), p.IsNamespaced(), p.Namespace, clusterResources)...) return errs } diff --git a/api/kyverno/v2beta1/policy_types.go b/api/kyverno/v2beta1/policy_types.go index 5fd55513e4..1227427ba6 100644 --- a/api/kyverno/v2beta1/policy_types.go +++ b/api/kyverno/v2beta1/policy_types.go @@ -105,7 +105,7 @@ func (p *Policy) IsReady() bool { func (p *Policy) Validate(clusterResources sets.Set[string]) (errs field.ErrorList) { errs = append(errs, kyvernov1.ValidateAutogenAnnotation(field.NewPath("metadata").Child("annotations"), p.GetAnnotations())...) errs = append(errs, kyvernov1.ValidatePolicyName(field.NewPath("name"), p.Name)...) - errs = append(errs, p.Spec.Validate(field.NewPath("spec"), p.IsNamespaced(), clusterResources)...) + errs = append(errs, p.Spec.Validate(field.NewPath("spec"), p.IsNamespaced(), p.Namespace, clusterResources)...) return errs } diff --git a/api/kyverno/v2beta1/rule_test.go b/api/kyverno/v2beta1/rule_test.go index cb9acbe988..1a00c058ea 100644 --- a/api/kyverno/v2beta1/rule_test.go +++ b/api/kyverno/v2beta1/rule_test.go @@ -13,7 +13,7 @@ func Test_Validate_RuleType_EmptyRule(t *testing.T) { Name: "validate-user-privilege", } path := field.NewPath("dummy") - errs := subject.Validate(path, false, nil) + errs := subject.Validate(path, false, "", nil) assert.Equal(t, len(errs), 1) assert.Equal(t, errs[0].Field, "dummy") assert.Equal(t, errs[0].Type, field.ErrorTypeInvalid) @@ -94,7 +94,7 @@ func Test_Validate_RuleType_MultipleRule(t *testing.T) { assert.NilError(t, err) for _, rule := range policy.Spec.Rules { path := field.NewPath("dummy") - errs := rule.Validate(path, false, nil) + errs := rule.Validate(path, false, "", nil) assert.Assert(t, len(errs) != 0) } } @@ -153,7 +153,7 @@ func Test_Validate_RuleType_SingleRule(t *testing.T) { assert.NilError(t, err) for _, rule := range policy.Spec.Rules { path := field.NewPath("dummy") - errs := rule.Validate(path, false, nil) + errs := rule.Validate(path, false, "", nil) assert.Assert(t, len(errs) == 0) } } @@ -534,7 +534,7 @@ func Test_Validate_ClusterPolicy_Generate_Variables(t *testing.T) { var rule *Rule err := json.Unmarshal(testcase.rule, &rule) assert.NilError(t, err, testcase.name) - errs := rule.ValidateGenerate(path, nil) + errs := rule.ValidateGenerate(path, false, "", nil) assert.Equal(t, len(errs) != 0, testcase.shouldFail, testcase.name) } } diff --git a/api/kyverno/v2beta1/rule_types.go b/api/kyverno/v2beta1/rule_types.go index a7ec3b5d15..cc643a24e9 100644 --- a/api/kyverno/v2beta1/rule_types.go +++ b/api/kyverno/v2beta1/rule_types.go @@ -183,20 +183,20 @@ func (r *Rule) ValidateMatchExcludeConflict(path *field.Path) (errs field.ErrorL return append(errs, field.Invalid(path, r, "Rule is matching an empty set")) } -func (r *Rule) ValidateGenerate(path *field.Path, clusterResources sets.Set[string]) (errs field.ErrorList) { +func (r *Rule) ValidateGenerate(path *field.Path, namespaced bool, policyNamespace string, clusterResources sets.Set[string]) (errs field.ErrorList) { if !r.HasGenerate() { return nil } - return r.Generation.Validate(path, clusterResources) + return r.Generation.Validate(path, namespaced, policyNamespace, clusterResources) } // Validate implements programmatic validation -func (r *Rule) Validate(path *field.Path, namespaced bool, clusterResources sets.Set[string]) (errs field.ErrorList) { +func (r *Rule) Validate(path *field.Path, namespaced bool, policyNamespace string, clusterResources sets.Set[string]) (errs field.ErrorList) { errs = append(errs, r.ValidateRuleType(path)...) errs = append(errs, r.ValidateMatchExcludeConflict(path)...) errs = append(errs, r.MatchResources.Validate(path.Child("match"), namespaced, clusterResources)...) errs = append(errs, r.ExcludeResources.Validate(path.Child("exclude"), namespaced, clusterResources)...) - errs = append(errs, r.ValidateGenerate(path, clusterResources)...) + errs = append(errs, r.ValidateGenerate(path, namespaced, policyNamespace, clusterResources)...) return errs } diff --git a/api/kyverno/v2beta1/spec_test.go b/api/kyverno/v2beta1/spec_test.go index 4575edcf73..ff3f131d65 100644 --- a/api/kyverno/v2beta1/spec_test.go +++ b/api/kyverno/v2beta1/spec_test.go @@ -47,7 +47,7 @@ func Test_Validate_UniqueRuleName(t *testing.T) { }}, } path := field.NewPath("dummy") - errs := subject.Validate(path, false, nil) + errs := subject.Validate(path, false, "", nil) assert.Equal(t, len(errs), 1) assert.Equal(t, errs[0].Field, "dummy.rules[1].name") assert.Equal(t, errs[0].Type, field.ErrorTypeInvalid) diff --git a/api/kyverno/v2beta1/spec_types.go b/api/kyverno/v2beta1/spec_types.go index ae0f7bd71e..32009e79df 100644 --- a/api/kyverno/v2beta1/spec_types.go +++ b/api/kyverno/v2beta1/spec_types.go @@ -216,10 +216,10 @@ func (s *Spec) ValidateRuleNames(path *field.Path) (errs field.ErrorList) { } // ValidateRules implements programmatic validation of Rules -func (s *Spec) ValidateRules(path *field.Path, namespaced bool, clusterResources sets.Set[string]) (errs field.ErrorList) { +func (s *Spec) ValidateRules(path *field.Path, namespaced bool, policyNamespace string, clusterResources sets.Set[string]) (errs field.ErrorList) { errs = append(errs, s.ValidateRuleNames(path)...) for i, rule := range s.Rules { - errs = append(errs, rule.Validate(path.Index(i), namespaced, clusterResources)...) + errs = append(errs, rule.Validate(path.Index(i), namespaced, policyNamespace, clusterResources)...) } return errs } @@ -232,14 +232,14 @@ func (s *Spec) ValidateDeprecatedFields(path *field.Path) (errs field.ErrorList) } // Validate implements programmatic validation -func (s *Spec) Validate(path *field.Path, namespaced bool, clusterResources sets.Set[string]) (errs field.ErrorList) { +func (s *Spec) Validate(path *field.Path, namespaced bool, policyNamespace string, clusterResources sets.Set[string]) (errs field.ErrorList) { if err := s.ValidateDeprecatedFields(path); err != nil { errs = append(errs, err...) } if s.WebhookTimeoutSeconds != nil && (*s.WebhookTimeoutSeconds < 1 || *s.WebhookTimeoutSeconds > 30) { errs = append(errs, field.Invalid(path.Child("webhookTimeoutSeconds"), s.WebhookTimeoutSeconds, "the timeout value must be between 1 and 30 seconds")) } - errs = append(errs, s.ValidateRules(path.Child("rules"), namespaced, clusterResources)...) + errs = append(errs, s.ValidateRules(path.Child("rules"), namespaced, policyNamespace, clusterResources)...) if namespaced && len(s.ValidationFailureActionOverrides) > 0 { errs = append(errs, field.Forbidden(path.Child("validationFailureActionOverrides"), "Use of validationFailureActionOverrides is supported only with ClusterPolicy")) } diff --git a/pkg/validation/cleanuppolicy/validate.go b/pkg/validation/cleanuppolicy/validate.go index 52811148d9..0d36640002 100644 --- a/pkg/validation/cleanuppolicy/validate.go +++ b/pkg/validation/cleanuppolicy/validate.go @@ -33,6 +33,7 @@ func FetchClusteredResources(logger logr.Logger, client dclient.Interface) (sets for _, resList := range res { for _, r := range resList.APIResources { if !r.Namespaced { + clusterResources.Insert(resList.GroupVersion + "/" + r.Kind) clusterResources.Insert(r.Kind) } } diff --git a/pkg/validation/policy/generate.go b/pkg/validation/policy/generate.go index 1ce8e2451f..7634a041e8 100644 --- a/pkg/validation/policy/generate.go +++ b/pkg/validation/policy/generate.go @@ -8,8 +8,6 @@ import ( "fmt" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" - kubeutils "github.com/kyverno/kyverno/pkg/utils/kube" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" ) @@ -48,63 +46,6 @@ func immutableGenerateFields(new, old kyvernov1.PolicyInterface) error { return nil } -// checkClusterResourceInMatchAndExclude returns false if namespaced ClusterPolicy contains cluster wide resources in -// Match and Exclude block -func checkClusterResourceInMatchAndExclude(rule kyvernov1.Rule, clusterResources sets.Set[string], policyNamespace string, mock bool, res []*metav1.APIResourceList) error { - if !mock { - // Check for generate policy - // - if resource to be generated is namespaced resource then the namespace field - // should be mentioned - // - if resource to be generated is non namespaced resource then the namespace field - // should not be mentioned - if rule.HasGenerate() { - generateResourceKind := rule.Generation.Kind - for _, resList := range res { - for _, r := range resList.APIResources { - if r.Kind == generateResourceKind { - if r.Namespaced { - if rule.Generation.Namespace == "" { - return fmt.Errorf("path: spec.rules[%v]: please mention the namespace to generate a namespaced resource", rule.Name) - } - if rule.Generation.Namespace != policyNamespace { - return fmt.Errorf("path: spec.rules[%v]: a namespaced policy cannot generate resources in other namespaces, expected: %v, received: %v", rule.Name, policyNamespace, rule.Generation.Namespace) - } - if rule.Generation.Clone.Name != "" { - if rule.Generation.Clone.Namespace != policyNamespace { - return fmt.Errorf("path: spec.rules[%v]: a namespaced policy cannot clone resources to or from other namespaces, expected: %v, received: %v", rule.Name, policyNamespace, rule.Generation.Clone.Namespace) - } - } - } else { - if rule.Generation.Namespace != "" { - return fmt.Errorf("path: spec.rules[%v]: do not mention the namespace to generate a non namespaced resource", rule.Name) - } - if policyNamespace != "" { - return fmt.Errorf("path: spec.rules[%v]: a namespaced policy cannot generate cluster-wide resources", rule.Name) - } - } - } else if len(rule.Generation.CloneList.Kinds) != 0 { - for _, kind := range rule.Generation.CloneList.Kinds { - _, splitkind := kubeutils.GetKindFromGVK(kind) - if r.Kind == splitkind { - if r.Namespaced { - if rule.Generation.CloneList.Namespace != policyNamespace { - return fmt.Errorf("path: spec.rules[%v]: a namespaced policy cannot clone resource in other namespace, expected: %v, received: %v", rule.Name, policyNamespace, rule.Generation.Namespace) - } - } else { - if policyNamespace != "" { - return fmt.Errorf("path: spec.rules[%v]: a namespaced policy cannot generate cluster-wide resources", rule.Name) - } - } - } - } - } - } - } - } - } - return nil -} - func resetMutableFields(rule kyvernov1.Rule) *kyvernov1.Rule { new := new(kyvernov1.Rule) rule.DeepCopyInto(new) diff --git a/pkg/validation/policy/validate.go b/pkg/validation/policy/validate.go index 5e8dd0b818..26e6471f86 100644 --- a/pkg/validation/policy/validate.go +++ b/pkg/validation/policy/validate.go @@ -165,6 +165,7 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf for _, resList := range res { for _, r := range resList.APIResources { if !r.Namespaced { + clusterResources.Insert(resList.GroupVersion + "/" + r.Kind) clusterResources.Insert(r.Kind) } } @@ -277,14 +278,6 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf } } - // validate Cluster Resources in namespaced policy - // For namespaced policy, ClusterResource type field and values are not allowed in match and exclude - if policy.IsNamespaced() { - if err := checkClusterResourceInMatchAndExclude(rule, clusterResources, policy.GetNamespace(), mock, res); err != nil { - return warnings, err - } - } - if err := validateActions(i, &rules[i], client, mock, username); err != nil { return warnings, err } diff --git a/pkg/validation/policy/validate_test.go b/pkg/validation/policy/validate_test.go index 6367018555..41c250b99b 100644 --- a/pkg/validation/policy/validate_test.go +++ b/pkg/validation/policy/validate_test.go @@ -13,7 +13,6 @@ import ( "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" ) @@ -1094,136 +1093,6 @@ func Test_Namespced_Policy(t *testing.T) { assert.Assert(t, err != nil) } -func Test_Namespaced_Generate_Policy(t *testing.T) { - testcases := []struct { - description string - rule []byte - policyNamespace string - expectedError error - }{ - { - description: "Only generate resource where the policy exists", - rule: []byte(` - {"name": "gen-zk", - "generate": { - "synchronize": false, - "apiVersion": "v1", - "kind": "ConfigMap", - "name": "zk", - "namespace": "default", - "data": { - "kind": "ConfigMap", - "metadata": { - "labels": { - "somekey": "somevalue" - } - }, - "data": { - "ZK_ADDRESS": "192.168.10.10:2181", - "KAFKA_ADDRESS": "192.168.10.13:9092" - } - } - } - }`), - policyNamespace: "poltest", - expectedError: errors.New("path: spec.rules[gen-zk]: a namespaced policy cannot generate resources in other namespaces, expected: poltest, received: default"), - }, - { - description: "Not allowed to clone resource outside the policy namespace", - rule: []byte(` - { - "name": "sync-image-pull-secret", - "generate": { - "apiVersion": "v1", - "kind": "Secret", - "name": "secret-basic-auth-gen", - "namespace": "poltest", - "synchronize": true, - "clone": { - "namespace": "default", - "name": "secret-basic-auth" - } - } - }`), - policyNamespace: "poltest", - expectedError: errors.New("path: spec.rules[sync-image-pull-secret]: a namespaced policy cannot clone resources to or from other namespaces, expected: poltest, received: default"), - }, - { - description: "Do not mention the namespace to generate cluster scoped resource", - rule: []byte(` - { - "name": "sync-clone", - "generate": { - "apiVersion": "storage.k8s.io/v1", - "kind": "StorageClass", - "name": "local-class", - "namespace": "poltest", - "synchronize": true, - "clone": { - "name": "pv-class" - } - } - }`), - policyNamespace: "poltest", - expectedError: errors.New("path: spec.rules[sync-clone]: do not mention the namespace to generate a non namespaced resource"), - }, - { - description: "Not allowed to clone cluster scoped resource", - rule: []byte(` - { - "name": "sync-clone", - "generate": { - "apiVersion": "storage.k8s.io/v1", - "kind": "StorageClass", - "name": "local-class", - "synchronize": true, - "clone": { - "name": "pv-class" - } - } - }`), - policyNamespace: "poltest", - expectedError: errors.New("path: spec.rules[sync-clone]: a namespaced policy cannot generate cluster-wide resources"), - }, - { - description: "Not allowed to multi clone cluster scoped resource", - rule: []byte(` - { - "name": "sync-multi-clone", - "generate": { - "namespace": "staging", - "synchronize": true, - "cloneList": { - "namespace": "staging", - "kinds": [ - "storage.k8s.io/v1/StorageClass" - ], - "selector": { - "matchLabels": { - "allowedToBeCloned": "true" - } - } - } - } - }`), - policyNamespace: "staging", - expectedError: errors.New("path: spec.rules[sync-multi-clone]: a namespaced policy cannot generate cluster-wide resources"), - }, - } - for _, tc := range testcases { - t.Run(tc.description, func(t *testing.T) { - var rule kyverno.Rule - _ = json.Unmarshal(tc.rule, &rule) - err := checkClusterResourceInMatchAndExclude(rule, sets.New[string](), tc.policyNamespace, false, testResourceList()) - if tc.expectedError != nil { - assert.Error(t, err, tc.expectedError.Error()) - } else { - assert.NilError(t, err) - } - }) - } -} - func Test_patchesJson6902_Policy(t *testing.T) { rawPolicy := []byte(` { diff --git a/test/cli/test-generate/create-default-pdb/policy.yaml b/test/cli/test-generate/create-default-pdb/policy.yaml index 3ae3fb037f..a96c53eb57 100644 --- a/test/cli/test-generate/create-default-pdb/policy.yaml +++ b/test/cli/test-generate/create-default-pdb/policy.yaml @@ -1,15 +1,27 @@ apiVersion: kyverno.io/v1 -kind: Policy +kind: ClusterPolicy metadata: name: create-default-pdb - namespace: hello-world + annotations: + policies.kyverno.io/title: Add Pod Disruption Budget + policies.kyverno.io/category: Sample + kyverno.io/kyverno-version: 1.6.2 + policies.kyverno.io/minversion: 1.6.0 + policies.kyverno.io/subject: Deployment + policies.kyverno.io/description: >- + A PodDisruptionBudget limits the number of Pods of a replicated application that + are down simultaneously from voluntary disruptions. For example, a quorum-based + application would like to ensure that the number of replicas running is never brought + below the number needed for a quorum. As an application owner, you can create a PodDisruptionBudget (PDB) + for each application. This policy will create a PDB resource whenever a new Deployment is created. spec: rules: - name: create-default-pdb match: - resources: - kinds: - - Deployment + any: + - resources: + kinds: + - Deployment generate: apiVersion: policy/v1 kind: PodDisruptionBudget diff --git a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-crd.yaml b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-crd.yaml new file mode 100644 index 0000000000..7b4fcae4f4 --- /dev/null +++ b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-crd.yaml @@ -0,0 +1,234 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + name: roles.iam.aws.crossplane.io +spec: + group: iam.aws.crossplane.io + names: + categories: + - crossplane + - managed + - aws + kind: Role + listKind: RoleList + plural: roles + shortNames: + - iamrole + singular: role + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: READY + type: string + - jsonPath: .status.conditions[?(@.type=='Synced')].status + name: SYNCED + type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: An Role is a managed resource that represents an AWS IAM Role. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: An RoleSpec defines the desired state of an Role. + properties: + deletionPolicy: + default: Delete + description: DeletionPolicy specifies what will happen to the underlying + external when this managed resource is deleted - either "Delete" + or "Orphan" the external resource. + enum: + - Orphan + - Delete + type: string + forProvider: + description: RoleParameters define the desired state of an AWS IAM + Role. + properties: + assumeRolePolicyDocument: + description: AssumeRolePolicyDocument is the the trust relationship + policy document that grants an entity permission to assume the + role. + type: string + description: + description: Description is a description of the role. + type: string + maxSessionDuration: + description: 'MaxSessionDuration is the duration (in seconds) + that you want to set for the specified role. The default maximum + of one hour is applied. This setting can have a value from 1 + hour to 12 hours. Default: 3600' + format: int32 + type: integer + path: + description: 'Path is the path to the role. Default: /' + type: string + permissionsBoundary: + description: PermissionsBoundary is the ARN of the policy that + is used to set the permissions boundary for the role. + type: string + tags: + description: Tags. For more information about tagging, see Tagging + IAM Identities (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_tags.html) + in the IAM User Guide. + items: + description: Tag represents user-provided metadata that can + be associated with a IAM role. For more information about + tagging, see Tagging IAM Identities (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_tags.html) + in the IAM User Guide. + properties: + key: + description: The key name that can be used to look up or + retrieve the associated value. For example, Department + or Cost Center are common choices. + type: string + value: + description: "The value associated with this tag. For example, + tags with a key name of Department could have values such + as Human Resources, Accounting, and Support. Tags with + a key name of Cost Center might have values that consist + of the number associated with the different cost centers + in your company. Typically, many resources have tags with + the same key name but with different values. \n AWS always + interprets the tag Value as a single string. If you need + to store an array, you can store comma-separated values + in the string. However, you must interpret the value in + your code." + type: string + required: + - key + type: object + type: array + required: + - assumeRolePolicyDocument + type: object + providerConfigRef: + default: + name: default + description: ProviderConfigReference specifies how the provider that + will be used to create, observe, update, and delete this managed + resource should be configured. + properties: + name: + description: Name of the referenced object. + type: string + required: + - name + type: object + providerRef: + description: 'ProviderReference specifies the provider that will be + used to create, observe, update, and delete this managed resource. + Deprecated: Please use ProviderConfigReference, i.e. `providerConfigRef`' + properties: + name: + description: Name of the referenced object. + type: string + required: + - name + type: object + writeConnectionSecretToRef: + description: WriteConnectionSecretToReference specifies the namespace + and name of a Secret to which any connection details for this managed + resource should be written. Connection details frequently include + the endpoint, username, and password required to connect to the + managed resource. + properties: + name: + description: Name of the secret. + type: string + namespace: + description: Namespace of the secret. + type: string + required: + - name + - namespace + type: object + required: + - forProvider + type: object + status: + description: An RoleStatus represents the observed state of an Role. + properties: + atProvider: + description: RoleExternalStatus keeps the state for the external resource + properties: + arn: + description: ARN is the Amazon Resource Name (ARN) specifying + the role. For more information about ARNs and how to use them + in policies, see IAM Identifiers (http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html) + in the IAM User Guide guide. + type: string + roleID: + description: RoleID is the stable and unique string identifying + the role. For more information about IDs, see IAM Identifiers + (http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html) + in the Using IAM guide. + type: string + required: + - arn + - roleID + type: object + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown? + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: + - v1beta1 \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-update-clusterrole.yaml b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-update-clusterrole.yaml new file mode 100644 index 0000000000..864c0d1a7c --- /dev/null +++ b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-update-clusterrole.yaml @@ -0,0 +1,20 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kyverno:background-controller:additional + labels: + app.kubernetes.io/component: background-controller + app.kubernetes.io/instance: kyverno + app.kubernetes.io/part-of: kyverno +rules: +- apiGroups: + - '*' + resources: + - namespaces + verbs: + - create + - update + - patch + - delete + - get + - list \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-fail.yaml b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/02-check.yaml similarity index 69% rename from test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-fail.yaml rename to test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/02-check.yaml index 64a5c70397..571d6bc6ce 100644 --- a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/01-fail.yaml +++ b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/02-check.yaml @@ -4,4 +4,6 @@ apply: - file: policy-namespaced-target.yaml shouldFail: true - file: policy-cluster-target.yaml - shouldFail: true \ No newline at end of file + shouldFail: false +- file: policy-pass.yaml + shouldFail: false \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/03-delete.yaml b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/03-delete.yaml new file mode 100644 index 0000000000..a728371431 --- /dev/null +++ b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/03-delete.yaml @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + name: roles.iam.aws.crossplane.io diff --git a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/04-delete.yaml b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/04-delete.yaml new file mode 100644 index 0000000000..67d9ba2b9b --- /dev/null +++ b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/04-delete.yaml @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + name: kyverno:background-controller:additional diff --git a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/README.md b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/README.md index 587390c88e..cd668aec99 100644 --- a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/README.md +++ b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/README.md @@ -9,4 +9,5 @@ The test fails if the policy creation is allowed, otherwise passes. ## Reference Issue(s) -https://github.com/kyverno/kyverno/issues/7038 \ No newline at end of file +https://github.com/kyverno/kyverno/issues/7038 +https://github.com/kyverno/kyverno/issues/7470 \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/policy-pass.yaml b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/policy-pass.yaml new file mode 100644 index 0000000000..050476b48e --- /dev/null +++ b/test/conformance/kuttl/generate/validation/clusterpolicy/target-namespace-scope/policy-pass.yaml @@ -0,0 +1,59 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: target-namespace-scope-pass-1 +spec: + generateExistingOnPolicyUpdate: true + rules: + - generate: + apiVersion: iam.aws.crossplane.io/v1beta1 + data: + rules: + - verbs: + - "*" + apiGroups: + - "*" + resources: + - "*" + kind: Role + name: superuser + namespace: "{{request.object.metadata.name}}" + synchronize: true + match: + any: + - resources: + kinds: + - Namespace + names: + - dev-* + name: role-per-namespace +--- +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: user-per-namespace-pass-2 +spec: + generateExistingOnPolicyUpdate: true + rules: + - generate: + apiVersion: rbac.authorization.k8s.io/v1 + data: + rules: + - verbs: + - "*" + apiGroups: + - "*" + resources: + - "*" + kind: Role + name: superuser + namespace: "{{request.object.metadata.name}}" + synchronize: true + match: + any: + - resources: + kinds: + - Namespace + names: + - dev-* + name: role-per-namespace \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/policy.yaml b/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/policy.yaml index 347351737d..e5b4787831 100644 --- a/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/policy.yaml +++ b/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/policy.yaml @@ -13,7 +13,7 @@ spec: kinds: - ConfigMap generate: - namespace: "{{request.object.metadata.name}}" + namespace: default synchronize : true cloneList: namespace: default diff --git a/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-kinds.yaml b/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-kinds.yaml index 9d3c5acbfb..62bc618921 100644 --- a/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-kinds.yaml +++ b/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-kinds.yaml @@ -13,7 +13,7 @@ spec: kinds: - ConfigMap generate: - namespace: "{{request.object.metadata.name}}" + namespace: default synchronize : true cloneList: namespace: default diff --git a/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-ns.yaml b/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-ns.yaml index 8ca170c663..8681d01c05 100644 --- a/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-ns.yaml +++ b/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-ns.yaml @@ -13,7 +13,7 @@ spec: kinds: - ConfigMap generate: - namespace: "{{request.object.metadata.name}}" + namespace: default synchronize : true cloneList: namespace: update-clonelist-ns diff --git a/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-selector.yaml b/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-selector.yaml index c954047483..8ef1934da1 100644 --- a/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-selector.yaml +++ b/test/conformance/kuttl/generate/validation/policy/immutable-clonelist/update-selector.yaml @@ -13,7 +13,7 @@ spec: kinds: - generate: - namespace: "{{request.object.metadata.name}}" + namespace: default synchronize : true cloneList: namespace: default diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/01-crd.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/01-crd.yaml new file mode 100644 index 0000000000..7b4fcae4f4 --- /dev/null +++ b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/01-crd.yaml @@ -0,0 +1,234 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + name: roles.iam.aws.crossplane.io +spec: + group: iam.aws.crossplane.io + names: + categories: + - crossplane + - managed + - aws + kind: Role + listKind: RoleList + plural: roles + shortNames: + - iamrole + singular: role + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: READY + type: string + - jsonPath: .status.conditions[?(@.type=='Synced')].status + name: SYNCED + type: string + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + name: v1beta1 + schema: + openAPIV3Schema: + description: An Role is a managed resource that represents an AWS IAM Role. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: An RoleSpec defines the desired state of an Role. + properties: + deletionPolicy: + default: Delete + description: DeletionPolicy specifies what will happen to the underlying + external when this managed resource is deleted - either "Delete" + or "Orphan" the external resource. + enum: + - Orphan + - Delete + type: string + forProvider: + description: RoleParameters define the desired state of an AWS IAM + Role. + properties: + assumeRolePolicyDocument: + description: AssumeRolePolicyDocument is the the trust relationship + policy document that grants an entity permission to assume the + role. + type: string + description: + description: Description is a description of the role. + type: string + maxSessionDuration: + description: 'MaxSessionDuration is the duration (in seconds) + that you want to set for the specified role. The default maximum + of one hour is applied. This setting can have a value from 1 + hour to 12 hours. Default: 3600' + format: int32 + type: integer + path: + description: 'Path is the path to the role. Default: /' + type: string + permissionsBoundary: + description: PermissionsBoundary is the ARN of the policy that + is used to set the permissions boundary for the role. + type: string + tags: + description: Tags. For more information about tagging, see Tagging + IAM Identities (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_tags.html) + in the IAM User Guide. + items: + description: Tag represents user-provided metadata that can + be associated with a IAM role. For more information about + tagging, see Tagging IAM Identities (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_tags.html) + in the IAM User Guide. + properties: + key: + description: The key name that can be used to look up or + retrieve the associated value. For example, Department + or Cost Center are common choices. + type: string + value: + description: "The value associated with this tag. For example, + tags with a key name of Department could have values such + as Human Resources, Accounting, and Support. Tags with + a key name of Cost Center might have values that consist + of the number associated with the different cost centers + in your company. Typically, many resources have tags with + the same key name but with different values. \n AWS always + interprets the tag Value as a single string. If you need + to store an array, you can store comma-separated values + in the string. However, you must interpret the value in + your code." + type: string + required: + - key + type: object + type: array + required: + - assumeRolePolicyDocument + type: object + providerConfigRef: + default: + name: default + description: ProviderConfigReference specifies how the provider that + will be used to create, observe, update, and delete this managed + resource should be configured. + properties: + name: + description: Name of the referenced object. + type: string + required: + - name + type: object + providerRef: + description: 'ProviderReference specifies the provider that will be + used to create, observe, update, and delete this managed resource. + Deprecated: Please use ProviderConfigReference, i.e. `providerConfigRef`' + properties: + name: + description: Name of the referenced object. + type: string + required: + - name + type: object + writeConnectionSecretToRef: + description: WriteConnectionSecretToReference specifies the namespace + and name of a Secret to which any connection details for this managed + resource should be written. Connection details frequently include + the endpoint, username, and password required to connect to the + managed resource. + properties: + name: + description: Name of the secret. + type: string + namespace: + description: Namespace of the secret. + type: string + required: + - name + - namespace + type: object + required: + - forProvider + type: object + status: + description: An RoleStatus represents the observed state of an Role. + properties: + atProvider: + description: RoleExternalStatus keeps the state for the external resource + properties: + arn: + description: ARN is the Amazon Resource Name (ARN) specifying + the role. For more information about ARNs and how to use them + in policies, see IAM Identifiers (http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html) + in the IAM User Guide guide. + type: string + roleID: + description: RoleID is the stable and unique string identifying + the role. For more information about IDs, see IAM Identifiers + (http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html) + in the Using IAM guide. + type: string + required: + - arn + - roleID + type: object + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown? + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: + - v1beta1 \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/01-fail.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/01-fail.yaml deleted file mode 100644 index f50ac6fc25..0000000000 --- a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/01-fail.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: kuttl.dev/v1beta1 -kind: TestStep -apply: -- file: policy-namespaced-target.yaml - shouldFail: true \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/02-check.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/02-check.yaml new file mode 100644 index 0000000000..a8a18b0534 --- /dev/null +++ b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/02-check.yaml @@ -0,0 +1,13 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +apply: +- file: policy-pass.yaml + shouldFail: false +- file: policy-fail-0.yaml + shouldFail: true +- file: policy-fail-1.yaml + shouldFail: true +- file: policy-fail-2.yaml + shouldFail: true +- file: policy-fail-3.yaml + shouldFail: true \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/03-delete.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/03-delete.yaml new file mode 100644 index 0000000000..a728371431 --- /dev/null +++ b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/03-delete.yaml @@ -0,0 +1,6 @@ +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: +- apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + name: roles.iam.aws.crossplane.io diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-namespaced-target.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-0.yaml similarity index 100% rename from test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-namespaced-target.yaml rename to test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-0.yaml diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-1.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-1.yaml new file mode 100644 index 0000000000..2291bdd1aa --- /dev/null +++ b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-1.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: kyverno.io/v1 +kind: Policy +metadata: + name: pol-target-namespace-scope-fail-1 + namespace: default +spec: + generateExistingOnPolicyUpdate: true + rules: + - generate: + apiVersion: iam.aws.crossplane.io/v1beta1 + data: + rules: + - verbs: + - "*" + apiGroups: + - "*" + resources: + - "*" + kind: Role + name: superuser + namespace: default + synchronize: true + match: + any: + - resources: + kinds: + - Secret + names: + - dev-* + name: role-per-namespace diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-2.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-2.yaml new file mode 100644 index 0000000000..81d76143de --- /dev/null +++ b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-2.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: kyverno.io/v1 +kind: Policy +metadata: + name: pol-target-namespace-scope-fail-2 + namespace: default +spec: + generateExistingOnPolicyUpdate: true + rules: + - generate: + apiVersion: rbac.authorization.k8s.io/v1 + data: + rules: + - verbs: + - "*" + apiGroups: + - "*" + resources: + - "*" + kind: Role + name: superuser + namespace: "{{request.object.metadata.name}}" + synchronize: true + match: + any: + - resources: + kinds: + - Secret + names: + - dev-* + name: role-per-namespace diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-3.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-3.yaml new file mode 100644 index 0000000000..41c369ce2d --- /dev/null +++ b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-fail-3.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: kyverno.io/v1 +kind: Policy +metadata: + name: pol-target-namespace-scope-fail-3 + namespace: default +spec: + generateExistingOnPolicyUpdate: true + rules: + - generate: + apiVersion: rbac.authorization.k8s.io/v1 + data: + rules: + - verbs: + - "*" + apiGroups: + - "*" + resources: + - "*" + kind: Role + name: superuser + namespace: test + synchronize: true + match: + any: + - resources: + kinds: + - Secret + names: + - dev-* + name: role-per-namespace \ No newline at end of file diff --git a/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-pass.yaml b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-pass.yaml new file mode 100644 index 0000000000..ec0d97e11c --- /dev/null +++ b/test/conformance/kuttl/generate/validation/policy/target-namespace-scope/policy-pass.yaml @@ -0,0 +1,30 @@ +apiVersion: kyverno.io/v1 +kind: Policy +metadata: + name: user-per-namespace-pass + namespace: default +spec: + generateExistingOnPolicyUpdate: true + rules: + - generate: + apiVersion: rbac.authorization.k8s.io/v1 + data: + rules: + - verbs: + - "*" + apiGroups: + - "*" + resources: + - "*" + kind: Role + name: superuser + namespace: default + synchronize: true + match: + any: + - resources: + kinds: + - Secret + names: + - dev-* + name: role-per-namespace