mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-05 07:26:55 +00:00
fix: add resourceNames field in the generated VAPs (#10187)
Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
parent
4bbb57af18
commit
3fa6a8d34e
13 changed files with 202 additions and 17 deletions
|
@ -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
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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 {
|
||||
|
@ -164,6 +169,7 @@ func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery,
|
|||
}
|
||||
if isNewRule {
|
||||
r := admissionregistrationv1alpha1.NamedRuleWithOperations{
|
||||
ResourceNames: resourceNames,
|
||||
RuleWithOperations: admissionregistrationv1.RuleWithOperations{
|
||||
Rule: admissionregistrationv1.Rule{
|
||||
Resources: resources,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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"
|
|
@ -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"
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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"
|
|
@ -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: {}
|
|
@ -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: {}
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue