Skip to content

Commit

Permalink
fix: add resourceNames field in the generated VAPs (#10187) (#10265)
Browse files Browse the repository at this point in the history
Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
Co-authored-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
  • Loading branch information
gcp-cherry-pick-bot[bot] and MariamFahmy98 committed May 20, 2024
1 parent 1365827 commit 41a3648
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 17 deletions.
14 changes: 10 additions & 4 deletions pkg/validatingadmissionpolicy/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func translateResourceFilters(discoveryClient dclient.IDiscovery, matchResources
}

func translateResource(discoveryClient dclient.IDiscovery, matchResources *admissionregistrationv1alpha1.MatchResources, rules *[]admissionregistrationv1alpha1.NamedRuleWithOperations, res kyvernov1.ResourceDescription) error {
err := constructValidatingAdmissionPolicyRules(discoveryClient, rules, res.Kinds, res.GetOperations())
err := constructValidatingAdmissionPolicyRules(discoveryClient, rules, res)
if err != nil {
return err
}
Expand All @@ -120,9 +120,14 @@ func translateResource(discoveryClient dclient.IDiscovery, matchResources *admis
return nil
}

func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery, rules *[]admissionregistrationv1alpha1.NamedRuleWithOperations, kinds []string, operations []string) error {
func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery, rules *[]admissionregistrationv1alpha1.NamedRuleWithOperations, res kyvernov1.ResourceDescription) error {
// translate operations to their corresponding values in validating admission policy.
ops := translateOperations(operations)
ops := translateOperations(res.GetOperations())

resourceNames := res.Names
if res.Name != "" {
resourceNames = append(resourceNames, res.Name)
}

// get kinds from kyverno policies and translate them to rules in validating admission policies.
// matched resources in kyverno policies are written in the following format:
Expand All @@ -131,7 +136,7 @@ func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery,
// apiGroups: ["group"]
// apiVersions: ["version"]
// resources: ["resource"]
for _, kind := range kinds {
for _, kind := range res.Kinds {
group, version, kind, subresource := kubeutils.ParseKindSelector(kind)
gvrss, err := discoveryClient.FindResources(group, version, kind, subresource)
if err != nil {
Expand Down Expand Up @@ -164,6 +169,7 @@ func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery,
}
if isNewRule {
r := admissionregistrationv1alpha1.NamedRuleWithOperations{
ResourceNames: resourceNames,
RuleWithOperations: admissionregistrationv1.RuleWithOperations{
Rule: admissionregistrationv1.Rule{
Resources: resources,
Expand Down
27 changes: 19 additions & 8 deletions pkg/validatingadmissionpolicy/kyvernopolicy_checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package validatingadmissionpolicy

import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/ext/wildcard"
)

// CanGenerateVAP check if Kyverno policy can be translated to a Kubernetes ValidatingAdmissionPolicy
func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) {
var msg string
if len(spec.Rules) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple rules aren't applicable."
msg = "skip generating ValidatingAdmissionPolicy: multiple rules are not applicable."
return false, msg
}

Expand All @@ -19,19 +20,19 @@ func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) {
}

if len(spec.ValidationFailureActionOverrides) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple validationFailureActionOverrides aren't applicable."
msg = "skip generating ValidatingAdmissionPolicy: multiple validationFailureActionOverrides are not applicable."
return false, msg
}

if len(spec.ValidationFailureActionOverrides) != 0 && len(spec.ValidationFailureActionOverrides[0].Namespaces) != 0 {
msg = "skip generating ValidatingAdmissionPolicy: Namespaces in validationFailureActionOverrides isn't applicable."
msg = "skip generating ValidatingAdmissionPolicy: Namespaces in validationFailureActionOverrides is not applicable."
return false, msg
}

// check the matched/excluded resources of the CEL rule.
match, exclude := rule.MatchResources, rule.ExcludeResources
if !exclude.UserInfo.IsEmpty() || !exclude.ResourceDescription.IsEmpty() || exclude.All != nil || exclude.Any != nil {
msg = "skip generating ValidatingAdmissionPolicy: Exclude isn't applicable."
msg = "skip generating ValidatingAdmissionPolicy: Exclude is not applicable."
return false, msg
}
if ok, msg := checkUserInfo(match.UserInfo); !ok {
Expand Down Expand Up @@ -65,14 +66,14 @@ func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) {
// since namespace/object selectors are applied to all NamedRuleWithOperations in ValidatingAdmissionPolicy, then
// we can't have more than one resource with namespace/object selectors.
if len(match.Any) > 1 && (containsNamespaceSelector || containsObjectSelector) {
msg = "skip generating ValidatingAdmissionPolicy: NamespaceSelector / ObjectSelector across multiple resources aren't applicable."
msg = "skip generating ValidatingAdmissionPolicy: NamespaceSelector / ObjectSelector across multiple resources are not applicable."
return false, msg
}

// since 'all' specify resources which will be ANDed, we can't have more than one resource.
if match.All != nil {
if len(match.All) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' isn't applicable."
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' is not applicable."
return false, msg
} else {
if ok, msg := checkUserInfo(match.All[0].UserInfo); !ok {
Expand All @@ -90,16 +91,26 @@ func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) {
func checkResources(resource kyvernov1.ResourceDescription) (bool, string) {
var msg string
if len(resource.Namespaces) != 0 || len(resource.Annotations) != 0 {
msg = "skip generating ValidatingAdmissionPolicy: Namespaces / Annotations in resource description isn't applicable."
msg = "skip generating ValidatingAdmissionPolicy: Namespaces / Annotations in resource description is not applicable."
return false, msg
}
if resource.Name != "" && wildcard.ContainsWildcard(resource.Name) {
msg = "skip generating ValidatingAdmissionPolicy: wildcards in resource name is not applicable."
return false, msg
}
for _, name := range resource.Names {
if wildcard.ContainsWildcard(name) {
msg = "skip generating ValidatingAdmissionPolicy: wildcards in resource name is not applicable."
return false, msg
}
}
return true, msg
}

func checkUserInfo(info kyvernov1.UserInfo) (bool, string) {
var msg string
if !info.IsEmpty() {
msg = "skip generating ValidatingAdmissionPolicy: Roles / ClusterRoles / Subjects in `any/all` isn't applicable."
msg = "skip generating ValidatingAdmissionPolicy: Roles / ClusterRoles / Subjects in `any/all` is not applicable."
return false, msg
}
return true, msg
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-any-match-resources-by-names
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml
- name: step-02
try:
- assert:
file: validatingadmissionpolicy.yaml
- assert:
file: validatingadmissionpolicybinding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-label-app-4
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready
validatingadmissionpolicy:
generated: true

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-label-app-4
spec:
validationFailureAction: Audit
rules:
- name: check-label-app
match:
any:
- resources:
kinds:
- Pod
- Deployment
names:
- "staging"
validate:
cel:
expressions:
- expression: "'app' in object.metadata.labels"
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: check-label-app-4
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: check-label-app-4
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resourceNames:
- staging
resources:
- pods
- pods/ephemeralcontainers
- apiGroups:
- apps
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resourceNames:
- staging
resources:
- deployments
validations:
- expression: "'app' in object.metadata.labels"
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: check-label-app-4-binding
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: check-label-app-4
spec:
policyName: check-label-app-4
validationActions:
- Audit
- Warn
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-any-match-resources-by-names-with-wildcard
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml
- name: step-02
try:
- error:
file: validatingadmissionpolicy.yaml
- error:
file: validatingadmissionpolicybinding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-label-app-3
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready
validatingadmissionpolicy:
generated: false

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-label-app-3
spec:
validationFailureAction: Audit
rules:
- name: check-label-app
match:
any:
- resources:
kinds:
- Pod
names:
- "prod-*"
- "staging"
validate:
cel:
expressions:
- expression: "'app' in object.metadata.labels"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: check-label-app-3
spec: {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: check-label-app-3-binding
spec: {}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ spec:
kinds:
- Pod
validate:
message: "The label `app` is required."
pattern:
metadata:
labels:
app: "?*"
cel:
expressions:
- expression: "'app' in object.metadata.labels"

0 comments on commit 41a3648

Please sign in to comment.