2022-05-16 16:36:21 +02:00
|
|
|
package resource
|
2022-01-21 18:06:44 +05:30
|
|
|
|
|
|
|
import (
|
2022-12-09 14:45:11 +01:00
|
|
|
"context"
|
2022-01-21 18:06:44 +05:30
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
2022-07-29 00:02:26 -07:00
|
|
|
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
2023-01-03 13:02:15 +01:00
|
|
|
"github.com/kyverno/kyverno/pkg/config"
|
2022-01-21 18:06:44 +05:30
|
|
|
"github.com/kyverno/kyverno/pkg/engine"
|
2023-06-14 12:06:52 +02:00
|
|
|
"github.com/kyverno/kyverno/pkg/engine/adapters"
|
2023-01-30 12:41:09 +01:00
|
|
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
2023-06-16 19:07:08 +05:30
|
|
|
"github.com/kyverno/kyverno/pkg/engine/factories"
|
2023-04-13 13:29:40 +02:00
|
|
|
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
2023-01-03 13:02:15 +01:00
|
|
|
log "github.com/kyverno/kyverno/pkg/logging"
|
|
|
|
"github.com/kyverno/kyverno/pkg/registryclient"
|
|
|
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
2022-09-08 10:36:31 +02:00
|
|
|
webhookutils "github.com/kyverno/kyverno/pkg/webhooks/utils"
|
2022-01-21 18:06:44 +05:30
|
|
|
"gotest.tools/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestValidate_failure_action_overrides(t *testing.T) {
|
|
|
|
testcases := []struct {
|
2023-01-18 05:21:34 -05:00
|
|
|
rawPolicy []byte
|
|
|
|
rawResource []byte
|
|
|
|
blocked bool
|
|
|
|
messages map[string]string
|
|
|
|
rawResourceNamespaceLabels map[string]string
|
2022-01-21 18:06:44 +05:30
|
|
|
}{
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "audit",
|
2023-01-02 18:14:40 +01:00
|
|
|
"validationFailureActionOverrides":
|
2022-01-21 18:06:44 +05:30
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"default"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"test"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "default"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "audit",
|
2023-01-02 18:14:40 +01:00
|
|
|
"validationFailureActionOverrides":
|
2022-01-21 18:06:44 +05:30
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"default"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"test"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"labels": {
|
|
|
|
"app": "my-app"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "audit",
|
2023-01-02 18:14:40 +01:00
|
|
|
"validationFailureActionOverrides":
|
2022-01-21 18:06:44 +05:30
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"default"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"test"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "test"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
2023-01-02 18:14:40 +01:00
|
|
|
"validationFailureActionOverrides":
|
2022-01-21 18:06:44 +05:30
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"default"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"test"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "default"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
2023-01-02 18:14:40 +01:00
|
|
|
"validationFailureActionOverrides":
|
2022-01-21 18:06:44 +05:30
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"default"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"test"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"labels": {
|
|
|
|
"app": "my-app"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
2023-01-02 18:14:40 +01:00
|
|
|
"validationFailureActionOverrides":
|
2022-01-21 18:06:44 +05:30
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"default"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"test"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "test"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
2023-01-02 18:14:40 +01:00
|
|
|
"validationFailureActionOverrides":
|
2022-01-21 18:06:44 +05:30
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"default"
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"test"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
2022-07-29 00:02:26 -07:00
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-01-21 18:06:44 +05:30
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": ""
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: true,
|
2022-07-29 00:02:26 -07:00
|
|
|
messages: map[string]string{
|
|
|
|
"check-label-app": "validation error: The label 'app' is required. rule check-label-app failed at path /metadata/labels/",
|
|
|
|
},
|
2022-01-21 18:06:44 +05:30
|
|
|
},
|
2023-01-18 05:21:34 -05:00
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
|
|
|
"validationFailureActionOverrides":
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"dev"
|
|
|
|
],
|
|
|
|
"namespaceSelector": {
|
|
|
|
"matchExpressions": [{
|
|
|
|
"key" : "kubernetes.io/metadata.name",
|
|
|
|
"operator": "In",
|
|
|
|
"values": [
|
|
|
|
"prod"
|
|
|
|
]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "default"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: true,
|
|
|
|
messages: map[string]string{
|
|
|
|
"check-label-app": "validation error: The label 'app' is required. rule check-label-app failed at path /metadata/labels/",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
|
|
|
"validationFailureActionOverrides":
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaceSelector": {
|
|
|
|
"matchExpressions": [{
|
|
|
|
"key" : "kubernetes.io/metadata.name",
|
|
|
|
"operator": "In",
|
|
|
|
"values": [
|
|
|
|
"prod"
|
|
|
|
]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "prod"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: false,
|
|
|
|
rawResourceNamespaceLabels: map[string]string{
|
|
|
|
"kubernetes.io/metadata.name": "prod",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
|
|
|
"validationFailureActionOverrides":
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaceSelector": {
|
|
|
|
"matchExpressions": [{
|
|
|
|
"key" : "kubernetes.io/metadata.name",
|
|
|
|
"operator": "In",
|
|
|
|
"values": [
|
|
|
|
"prod"
|
|
|
|
]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "default"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: true,
|
|
|
|
messages: map[string]string{
|
|
|
|
"check-label-app": "validation error: The label 'app' is required. rule check-label-app failed at path /metadata/labels/",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
|
|
|
"validationFailureActionOverrides":
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"dev"
|
|
|
|
],
|
|
|
|
"namespaceSelector": {
|
|
|
|
"matchExpressions": [{
|
|
|
|
"key" : "kubernetes.io/metadata.name",
|
|
|
|
"operator": "In",
|
|
|
|
"values": [
|
|
|
|
"prod"
|
|
|
|
]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "dev"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: true,
|
|
|
|
rawResourceNamespaceLabels: map[string]string{
|
|
|
|
"kubernetes.io/metadata.name": "dev",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
|
|
|
"validationFailureActionOverrides":
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "audit",
|
|
|
|
"namespaces": [
|
|
|
|
"dev"
|
|
|
|
],
|
|
|
|
"namespaceSelector": {
|
|
|
|
"matchExpressions": [{
|
|
|
|
"key" : "kubernetes.io/metadata.name",
|
|
|
|
"operator": "In",
|
|
|
|
"values": [
|
|
|
|
"prod"
|
|
|
|
]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "prod"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: true,
|
|
|
|
rawResourceNamespaceLabels: map[string]string{
|
|
|
|
"kubernetes.io/metadata.name": "prod",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "audit",
|
|
|
|
"validationFailureActionOverrides":
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"dev"
|
|
|
|
],
|
|
|
|
"namespaceSelector": {
|
|
|
|
"matchExpressions": [{
|
|
|
|
"key" : "kubernetes.io/metadata.name",
|
|
|
|
"operator": "In",
|
|
|
|
"values": [
|
|
|
|
"prod"
|
|
|
|
]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "dev"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: false,
|
|
|
|
rawResourceNamespaceLabels: map[string]string{
|
|
|
|
"kubernetes.io/metadata.name": "dev",
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
rawPolicy: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {
|
|
|
|
"name": "check-label-app"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "audit",
|
|
|
|
"validationFailureActionOverrides":
|
|
|
|
[
|
|
|
|
{
|
|
|
|
"action": "enforce",
|
|
|
|
"namespaces": [
|
|
|
|
"dev"
|
|
|
|
],
|
|
|
|
"namespaceSelector": {
|
|
|
|
"matchExpressions": [{
|
|
|
|
"key" : "kubernetes.io/metadata.name",
|
|
|
|
"operator": "In",
|
|
|
|
"values": [
|
|
|
|
"dev"
|
|
|
|
]
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-app",
|
|
|
|
"match": {
|
|
|
|
"resources": {
|
|
|
|
"kinds": [
|
|
|
|
"Pod"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
|
|
|
"pattern": {
|
|
|
|
"metadata": {
|
|
|
|
"labels": {
|
|
|
|
"app": "?*"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
rawResource: []byte(`
|
|
|
|
{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {
|
|
|
|
"name": "test-pod",
|
|
|
|
"namespace": "dev"
|
|
|
|
},
|
|
|
|
"spec": {
|
|
|
|
"containers": [
|
|
|
|
{
|
|
|
|
"name": "nginx",
|
|
|
|
"image": "nginx:latest"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`),
|
|
|
|
blocked: true,
|
|
|
|
rawResourceNamespaceLabels: map[string]string{
|
|
|
|
"kubernetes.io/metadata.name": "dev",
|
|
|
|
},
|
|
|
|
},
|
2022-01-21 18:06:44 +05:30
|
|
|
}
|
2023-04-13 13:29:40 +02:00
|
|
|
cfg := config.NewDefaultConfiguration(false)
|
|
|
|
jp := jmespath.New(cfg)
|
2023-06-14 12:06:52 +02:00
|
|
|
rclient := registryclient.NewOrDie()
|
2023-02-03 06:01:11 +01:00
|
|
|
eng := engine.NewEngine(
|
2023-04-13 13:29:40 +02:00
|
|
|
cfg,
|
2023-04-04 17:07:43 +02:00
|
|
|
config.NewDefaultMetricsConfiguration(),
|
2023-04-13 13:29:40 +02:00
|
|
|
jp,
|
2023-02-07 16:09:15 +01:00
|
|
|
nil,
|
2023-06-16 19:07:08 +05:30
|
|
|
factories.DefaultRegistryClientFactory(adapters.RegistryClient(rclient), nil),
|
|
|
|
factories.DefaultContextLoaderFactory(nil),
|
2023-02-06 06:49:47 +01:00
|
|
|
nil,
|
2023-06-02 14:18:10 +02:00
|
|
|
"",
|
2023-02-03 06:01:11 +01:00
|
|
|
)
|
2022-01-21 18:06:44 +05:30
|
|
|
for i, tc := range testcases {
|
|
|
|
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
2022-07-29 00:02:26 -07:00
|
|
|
var policy kyvernov1.ClusterPolicy
|
2022-01-21 18:06:44 +05:30
|
|
|
err := json.Unmarshal(tc.rawPolicy, &policy)
|
|
|
|
assert.NilError(t, err)
|
2023-01-03 13:02:15 +01:00
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(tc.rawResource)
|
2022-01-21 18:06:44 +05:30
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2023-05-12 16:14:48 +02:00
|
|
|
ctx, err := engine.NewPolicyContext(
|
|
|
|
jp,
|
|
|
|
*resourceUnstructured,
|
|
|
|
kyvernov1.Create,
|
|
|
|
nil,
|
|
|
|
cfg,
|
|
|
|
)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
ctx = ctx.WithPolicy(&policy).WithNamespaceLabels(tc.rawResourceNamespaceLabels)
|
2023-02-02 11:58:34 +01:00
|
|
|
er := eng.Validate(
|
2022-12-09 14:45:11 +01:00
|
|
|
context.TODO(),
|
2023-01-31 15:30:40 +01:00
|
|
|
ctx,
|
2022-12-02 09:14:23 +01:00
|
|
|
)
|
2022-07-29 00:02:26 -07:00
|
|
|
if tc.blocked && tc.messages != nil {
|
|
|
|
for _, r := range er.PolicyResponse.Rules {
|
2023-04-05 12:35:38 +02:00
|
|
|
msg := tc.messages[r.Name()]
|
|
|
|
assert.Equal(t, r.Message(), msg)
|
2022-01-21 18:06:44 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-02 07:54:02 -07:00
|
|
|
failurePolicy := kyvernov1.Fail
|
2023-03-23 13:58:52 +01:00
|
|
|
blocked := webhookutils.BlockRequest([]engineapi.EngineResponse{er}, failurePolicy, log.WithName("WebhookServer"))
|
2022-01-21 18:06:44 +05:30
|
|
|
assert.Assert(t, tc.blocked == blocked)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-07-29 00:02:26 -07:00
|
|
|
|
|
|
|
func Test_RuleSelector(t *testing.T) {
|
|
|
|
var rawPolicy = []byte(`{
|
|
|
|
"apiVersion": "kyverno.io/v1",
|
|
|
|
"kind": "ClusterPolicy",
|
|
|
|
"metadata": {"name": "check-label-app"},
|
|
|
|
"spec": {
|
|
|
|
"validationFailureAction": "enforce",
|
|
|
|
"rules": [
|
|
|
|
{
|
|
|
|
"name": "check-label-test",
|
|
|
|
"match": {"name": "test-*", "resources": {"kinds": ["Pod"]}},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
2023-01-02 18:14:40 +01:00
|
|
|
"pattern": { "metadata": { "labels": { "app": "?*" } } }
|
2022-07-29 00:02:26 -07:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "check-labels",
|
|
|
|
"match": {"name": "*", "resources": {"kinds": ["Pod"]}},
|
|
|
|
"validate": {
|
|
|
|
"message": "The label 'app' is required.",
|
2023-01-02 18:14:40 +01:00
|
|
|
"pattern": { "metadata": { "labels": { "app": "?*", "test" : "?*" } } }
|
2022-07-29 00:02:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`)
|
|
|
|
|
|
|
|
var rawResource = []byte(`{
|
|
|
|
"apiVersion": "v1",
|
|
|
|
"kind": "Pod",
|
|
|
|
"metadata": {"name": "test-pod", "namespace": "", "labels": { "app" : "test-pod" }},
|
|
|
|
"spec": {"containers": [{"name": "nginx", "image": "nginx:latest"}]}
|
|
|
|
}`)
|
|
|
|
|
|
|
|
var policy kyvernov1.ClusterPolicy
|
|
|
|
err := json.Unmarshal(rawPolicy, &policy)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
2023-01-03 13:02:15 +01:00
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(rawResource)
|
2022-07-29 00:02:26 -07:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Assert(t, resourceUnstructured != nil)
|
|
|
|
|
2023-04-13 13:29:40 +02:00
|
|
|
cfg := config.NewDefaultConfiguration(false)
|
|
|
|
jp := jmespath.New(cfg)
|
2023-05-12 16:14:48 +02:00
|
|
|
ctx, err := engine.NewPolicyContext(
|
|
|
|
jp,
|
|
|
|
*resourceUnstructured,
|
|
|
|
kyvernov1.Create,
|
|
|
|
nil,
|
|
|
|
cfg,
|
|
|
|
)
|
|
|
|
assert.NilError(t, err)
|
|
|
|
|
|
|
|
ctx = ctx.WithPolicy(&policy)
|
2023-06-14 12:06:52 +02:00
|
|
|
rclient := registryclient.NewOrDie()
|
2023-02-03 06:01:11 +01:00
|
|
|
eng := engine.NewEngine(
|
2023-04-13 13:29:40 +02:00
|
|
|
cfg,
|
2023-04-04 17:07:43 +02:00
|
|
|
config.NewDefaultMetricsConfiguration(),
|
2023-04-13 13:29:40 +02:00
|
|
|
jp,
|
2023-02-07 16:09:15 +01:00
|
|
|
nil,
|
2023-06-16 19:07:08 +05:30
|
|
|
factories.DefaultRegistryClientFactory(adapters.RegistryClient(rclient), nil),
|
|
|
|
factories.DefaultContextLoaderFactory(nil),
|
2023-02-06 06:49:47 +01:00
|
|
|
nil,
|
2023-06-02 14:18:10 +02:00
|
|
|
"",
|
2023-02-03 06:01:11 +01:00
|
|
|
)
|
2023-02-02 11:58:34 +01:00
|
|
|
resp := eng.Validate(
|
2023-01-31 15:30:40 +01:00
|
|
|
context.TODO(),
|
|
|
|
ctx,
|
|
|
|
)
|
2023-04-12 18:20:42 +02:00
|
|
|
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount() == 2)
|
|
|
|
assert.Assert(t, resp.PolicyResponse.RulesErrorCount() == 0)
|
2022-07-29 00:02:26 -07:00
|
|
|
|
2022-10-02 20:45:03 +01:00
|
|
|
log := log.WithName("Test_RuleSelector")
|
2023-03-23 13:58:52 +01:00
|
|
|
blocked := webhookutils.BlockRequest([]engineapi.EngineResponse{resp}, kyvernov1.Fail, log)
|
2022-07-29 00:02:26 -07:00
|
|
|
assert.Assert(t, blocked == true)
|
|
|
|
|
|
|
|
applyOne := kyvernov1.ApplyOne
|
|
|
|
policy.Spec.ApplyRules = &applyOne
|
2023-02-02 11:58:34 +01:00
|
|
|
resp = eng.Validate(
|
2023-01-31 15:30:40 +01:00
|
|
|
context.TODO(),
|
|
|
|
ctx,
|
|
|
|
)
|
2023-04-12 18:20:42 +02:00
|
|
|
assert.Assert(t, resp.PolicyResponse.RulesAppliedCount() == 1)
|
|
|
|
assert.Assert(t, resp.PolicyResponse.RulesErrorCount() == 0)
|
2022-07-29 00:02:26 -07:00
|
|
|
|
2023-03-23 13:58:52 +01:00
|
|
|
blocked = webhookutils.BlockRequest([]engineapi.EngineResponse{resp}, kyvernov1.Fail, log)
|
2022-07-29 00:02:26 -07:00
|
|
|
assert.Assert(t, blocked == false)
|
|
|
|
}
|