1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

fix: generate VAPs that match all resources when kinds is set to * (#10208)

Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
Mariam Fahmy 2024-05-09 14:46:10 +08:00 committed by GitHub
parent 60e347bedb
commit 6fec52436a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 147 additions and 40 deletions

View file

@ -150,55 +150,69 @@ func constructValidatingAdmissionPolicyRules(discoveryClient dclient.IDiscovery,
// apiVersions: ["version"]
// resources: ["resource"]
for _, kind := range res.Kinds {
group, version, kind, subresource := kubeutils.ParseKindSelector(kind)
gvrss, err := discoveryClient.FindResources(group, version, kind, subresource)
if err != nil {
return err
}
if len(gvrss) != 1 {
return fmt.Errorf("no unique match for kind %s", kind)
}
var r admissionregistrationv1alpha1.NamedRuleWithOperations
for topLevelApi, apiResource := range gvrss {
var resources []string
resources = append(resources, apiResource.Name)
// if we have pods, we add pods/ephemeralcontainers by default
if apiResource.Name == "pods" {
resources = append(resources, "pods/ephemeralcontainers")
if kind == "*" {
r = buildNamedRuleWithOperations(resourceNames, "*", "*", ops, "*")
*rules = append(*rules, r)
} else {
group, version, kind, subresource := kubeutils.ParseKindSelector(kind)
gvrss, err := discoveryClient.FindResources(group, version, kind, subresource)
if err != nil {
return err
}
if len(gvrss) != 1 {
return fmt.Errorf("no unique match for kind %s", kind)
}
isNewRule := true
// If there's a rule that contains both group and version, then the resource is appended to the existing rule instead of creating a new one.
// Example: apiGroups: ["apps"]
// apiVersions: ["v1"]
// resources: ["deployments", "statefulsets"]
// Otherwise, a new rule is created.
for i := range *rules {
if slices.Contains((*rules)[i].APIGroups, topLevelApi.Group) && slices.Contains((*rules)[i].APIVersions, topLevelApi.Version) {
(*rules)[i].Resources = append((*rules)[i].Resources, resources...)
isNewRule = false
break
for topLevelApi, apiResource := range gvrss {
resources := []string{apiResource.Name}
// Add pods/ephemeralcontainers if pods resource.
if apiResource.Name == "pods" {
resources = append(resources, "pods/ephemeralcontainers")
}
}
if isNewRule {
r := admissionregistrationv1alpha1.NamedRuleWithOperations{
ResourceNames: resourceNames,
RuleWithOperations: admissionregistrationv1.RuleWithOperations{
Rule: admissionregistrationv1.Rule{
Resources: resources,
APIGroups: []string{topLevelApi.Group},
APIVersions: []string{topLevelApi.Version},
},
Operations: ops,
},
// Check if there's an existing rule for the same group and version.
var isNewRule bool = true
for i := range *rules {
if slices.Contains((*rules)[i].APIGroups, topLevelApi.Group) && slices.Contains((*rules)[i].APIVersions, topLevelApi.Version) {
(*rules)[i].Resources = append((*rules)[i].Resources, resources...)
isNewRule = false
break
}
}
// If no existing rule found, create a new one.
if isNewRule {
r = buildNamedRuleWithOperations(resourceNames, topLevelApi.Group, topLevelApi.Version, ops, resources...)
*rules = append(*rules, r)
}
*rules = append(*rules, r)
}
}
}
return nil
}
func buildNamedRuleWithOperations(
resourceNames []string,
group, version string,
operations []admissionregistrationv1.OperationType,
resources ...string,
) admissionregistrationv1alpha1.NamedRuleWithOperations {
return admissionregistrationv1alpha1.NamedRuleWithOperations{
ResourceNames: resourceNames,
RuleWithOperations: admissionregistrationv1.RuleWithOperations{
Rule: admissionregistrationv1.Rule{
Resources: resources,
APIGroups: []string{group},
APIVersions: []string{version},
},
Operations: operations,
},
}
}
func translateOperations(operations []string) []admissionregistrationv1.OperationType {
var vapOperations []admissionregistrationv1.OperationType
for _, op := range operations {

View file

@ -0,0 +1,19 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-match-kind-with-wildcard
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

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-label-app4
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,21 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-label-app4
spec:
validationFailureAction: Audit
background: false
rules:
- name: check-label-app
match:
all:
- resources:
kinds:
- '*'
namespaces:
- production
- staging
validate:
cel:
expressions:
- expression: "'app' in object.metadata.labels"

View file

@ -0,0 +1,32 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: check-label-app4
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: check-label-app4
spec:
failurePolicy: Fail
matchConstraints:
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: In
values:
- production
- staging
resourceRules:
- apiGroups:
- '*'
apiVersions:
- '*'
operations:
- CREATE
- UPDATE
resources:
- '*'
validations:
- expression: '''app'' in object.metadata.labels'

View file

@ -0,0 +1,13 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: check-label-app4-binding
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: check-label-app4
spec:
policyName: check-label-app4
validationActions: [Audit, Warn]

View file

@ -7,6 +7,4 @@ status:
- reason: Succeeded
status: "True"
type: Ready
validatingadmissionpolicy:
generated: true