2019-05-16 21:37:54 +03:00
package engine
import (
"encoding/json"
"testing"
2019-11-13 13:41:08 -08:00
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
2020-01-09 17:44:11 -08:00
"github.com/nirmata/kyverno/pkg/engine/context"
2020-01-07 17:06:17 -08:00
"github.com/nirmata/kyverno/pkg/engine/utils"
2019-05-16 21:37:54 +03:00
"gotest.tools/assert"
)
func TestGetAnchorsFromMap_ThereAreAnchors ( t * testing . T ) {
2019-06-04 17:33:21 +03:00
rawMap := [ ] byte ( ` {
"(name)" : "nirmata-*" ,
"notAnchor1" : 123 ,
"(namespace)" : "kube-?olicy" ,
"notAnchor2" : "sample-text" ,
"object" : {
"key1" : "value1" ,
"(key2)" : "value2"
}
} ` )
2019-05-16 21:37:54 +03:00
var unmarshalled map [ string ] interface { }
json . Unmarshal ( rawMap , & unmarshalled )
2020-01-07 17:06:17 -08:00
actualMap := utils . GetAnchorsFromMap ( unmarshalled )
2019-05-16 21:37:54 +03:00
assert . Equal ( t , len ( actualMap ) , 2 )
assert . Equal ( t , actualMap [ "(name)" ] . ( string ) , "nirmata-*" )
assert . Equal ( t , actualMap [ "(namespace)" ] . ( string ) , "kube-?olicy" )
}
2019-09-25 15:12:33 -07:00
func TestValidate_image_tag_fail ( t * testing . T ) {
// If image tag is latest then imagepull policy needs to be checked
2019-09-05 12:44:38 -07:00
rawPolicy := [ ] byte ( ` {
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-05 12:44:38 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "validate-image"
} ,
"spec" : {
"rules" : [
{
"name" : "validate-tag" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "An image tag is required" ,
"pattern" : {
"spec" : {
"containers" : [
{
"image" : "*:*"
}
]
}
}
}
} ,
{
"name" : "validate-latest" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "imagePullPolicy 'Always' required with tag 'latest'" ,
"pattern" : {
"spec" : {
"containers" : [
{
2019-09-26 11:00:30 -07:00
"(image)" : "*latest" ,
2019-09-25 15:12:33 -07:00
"imagePullPolicy" : "NotPresent"
2019-09-05 12:44:38 -07:00
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "myapp"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx" ,
2019-09-25 15:12:33 -07:00
"image" : "nginx:latest" ,
"imagePullPolicy" : "Always"
2019-09-05 12:44:38 -07:00
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-05 12:44:38 -07:00
assert . NilError ( t , err )
2019-10-01 12:35:14 -07:00
msgs := [ ] string {
2019-11-04 20:15:44 -08:00
"Validation rule 'validate-tag' succeeded." ,
2019-12-04 18:04:42 -08:00
"Validation error: imagePullPolicy 'Always' required with tag 'latest'; Validation rule 'validate-latest' failed at path '/spec/containers/0/imagePullPolicy/'" ,
2019-10-01 12:35:14 -07:00
}
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-10-01 12:35:14 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
2019-09-05 12:44:38 -07:00
assert . Assert ( t , ! er . IsSuccesful ( ) )
}
2019-09-25 15:12:33 -07:00
func TestValidate_image_tag_pass ( t * testing . T ) {
// If image tag is latest then imagepull policy needs to be checked
rawPolicy := [ ] byte ( ` {
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 15:12:33 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "validate-image"
} ,
"spec" : {
"rules" : [
{
"name" : "validate-tag" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "An image tag is required" ,
"pattern" : {
"spec" : {
"containers" : [
{
"image" : "*:*"
}
]
}
}
}
} ,
{
"name" : "validate-latest" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "imagePullPolicy 'Always' required with tag 'latest'" ,
"pattern" : {
"spec" : {
"containers" : [
{
2019-09-26 11:00:30 -07:00
"(image)" : "*latest" ,
2019-09-25 15:12:33 -07:00
"imagePullPolicy" : "Always"
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "myapp"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx" ,
"image" : "nginx:latest" ,
"imagePullPolicy" : "Always"
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 15:12:33 -07:00
assert . NilError ( t , err )
2019-10-01 12:35:14 -07:00
msgs := [ ] string {
2019-11-04 20:15:44 -08:00
"Validation rule 'validate-tag' succeeded." ,
"Validation rule 'validate-latest' succeeded." ,
2019-10-01 12:35:14 -07:00
}
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-10-01 12:35:14 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
2019-09-25 15:12:33 -07:00
assert . Assert ( t , er . IsSuccesful ( ) )
}
2019-09-05 12:44:38 -07:00
func TestValidate_Fail_anyPattern ( t * testing . T ) {
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-05 12:44:38 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "validate-namespace"
} ,
"spec" : {
"rules" : [
{
"name" : "check-default-namespace" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "A namespace is required" ,
"anyPattern" : [
{
"metadata" : {
"namespace" : "?*"
}
} ,
{
"metadata" : {
"namespace" : "!default"
}
}
]
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "myapp"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx" ,
"image" : "nginx"
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-05 12:44:38 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2020-02-14 11:59:28 -08:00
msgs := [ ] string { "Validation rule 'check-default-namespace' failed. [anyPattern[0] failed; Validation rule failed at '/metadata/namespace/' to validate value '<nil>' with pattern '?*' anyPattern[1] failed; Validation rule failed at '/metadata/namespace/' to validate value '<nil>' with pattern '!default']" }
2019-09-05 12:44:38 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , ! er . IsSuccesful ( ) )
}
2019-09-09 16:08:15 -07:00
func TestValidate_host_network_port ( t * testing . T ) {
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-09 16:08:15 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "validate-host-network-port"
} ,
"spec" : {
"rules" : [
{
"name" : "validate-host-network-port" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "Host network and port are not allowed" ,
"pattern" : {
"spec" : {
"hostNetwork" : false ,
"containers" : [
{
"name" : "*" ,
"ports" : [
{
"hostPort" : null
}
]
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "nginx-host-network"
} ,
"spec" : {
"hostNetwork" : false ,
"containers" : [
{
"name" : "nginx-host-network" ,
"image" : "nginx" ,
"ports" : [
{
"containerPort" : 80 ,
"hostPort" : 80
}
]
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-09 16:08:15 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-12-04 18:04:42 -08:00
msgs := [ ] string { "Validation error: Host network and port are not allowed; Validation rule 'validate-host-network-port' failed at path '/spec/containers/0/ports/0/hostPort/'" }
2019-09-09 16:08:15 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , ! er . IsSuccesful ( ) )
}
2019-09-25 15:12:33 -07:00
func TestValidate_anchor_arraymap_pass ( t * testing . T ) {
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 15:12:33 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "validate-host-path"
} ,
"spec" : {
"rules" : [
{
"name" : "validate-host-path" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "Host path '/var/lib/' is not allowed" ,
"pattern" : {
"spec" : {
"volumes" : [
{
"name" : "*" ,
2019-10-01 13:08:34 -07:00
"=(hostPath)" : {
2019-09-25 15:12:33 -07:00
"path" : "!/var/lib"
}
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "image-with-hostpath" ,
"labels" : {
"app.type" : "prod" ,
"namespace" : "my-namespace"
}
} ,
"spec" : {
"containers" : [
{
"name" : "image-with-hostpath" ,
"image" : "docker.io/nautiker/curl" ,
"volumeMounts" : [
{
"name" : "var-lib-etcd" ,
"mountPath" : "/var/lib"
}
]
}
] ,
"volumes" : [
{
"name" : "var-lib-etcd" ,
"hostPath" : {
"path" : "/var/lib1"
}
}
]
}
} ` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 15:12:33 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-11-04 20:15:44 -08:00
msgs := [ ] string { "Validation rule 'validate-host-path' succeeded." }
2019-09-25 15:12:33 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , er . IsSuccesful ( ) )
}
func TestValidate_anchor_arraymap_fail ( t * testing . T ) {
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 15:12:33 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "validate-host-path"
} ,
"spec" : {
"rules" : [
{
"name" : "validate-host-path" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "Host path '/var/lib/' is not allowed" ,
"pattern" : {
"spec" : {
"volumes" : [
{
2019-10-01 13:08:34 -07:00
"=(hostPath)" : {
2019-09-25 15:12:33 -07:00
"path" : "!/var/lib"
}
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "image-with-hostpath" ,
"labels" : {
"app.type" : "prod" ,
"namespace" : "my-namespace"
}
} ,
"spec" : {
"containers" : [
{
"name" : "image-with-hostpath" ,
"image" : "docker.io/nautiker/curl" ,
"volumeMounts" : [
{
"name" : "var-lib-etcd" ,
"mountPath" : "/var/lib"
}
]
}
] ,
"volumes" : [
{
"name" : "var-lib-etcd" ,
"hostPath" : {
"path" : "/var/lib"
}
}
]
}
} ` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 15:12:33 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-12-04 18:04:42 -08:00
msgs := [ ] string { "Validation error: Host path '/var/lib/' is not allowed; Validation rule 'validate-host-path' failed at path '/spec/volumes/0/hostPath/path/'" }
2019-09-25 15:12:33 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , ! er . IsSuccesful ( ) )
}
func TestValidate_anchor_map_notfound ( t * testing . T ) {
// anchor not present in resource
rawPolicy := [ ] byte ( ` {
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 15:12:33 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "policy-secaas-k8s"
} ,
"spec" : {
"rules" : [
{
"name" : "pod rule 2" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "pod: validate run as non root user" ,
"pattern" : {
"spec" : {
2019-10-01 13:08:34 -07:00
"=(securityContext)" : {
2019-09-25 15:12:33 -07:00
"runAsNonRoot" : true
}
}
}
}
}
]
}
} ` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "v1"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx" ,
"image" : "nginx"
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 15:12:33 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-11-04 20:15:44 -08:00
msgs := [ ] string { "Validation rule 'pod rule 2' succeeded." }
2019-09-25 15:12:33 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , er . IsSuccesful ( ) )
}
func TestValidate_anchor_map_found_valid ( t * testing . T ) {
// anchor not present in resource
rawPolicy := [ ] byte ( ` {
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 15:12:33 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "policy-secaas-k8s"
} ,
"spec" : {
"rules" : [
{
"name" : "pod rule 2" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "pod: validate run as non root user" ,
"pattern" : {
"spec" : {
2019-10-01 13:08:34 -07:00
"=(securityContext)" : {
2019-09-25 15:12:33 -07:00
"runAsNonRoot" : true
}
}
}
}
}
]
}
} ` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "v1"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx" ,
"image" : "nginx"
}
] ,
"securityContext" : {
"runAsNonRoot" : true
}
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 15:12:33 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-11-04 20:15:44 -08:00
msgs := [ ] string { "Validation rule 'pod rule 2' succeeded." }
2019-09-25 15:12:33 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , er . IsSuccesful ( ) )
}
func TestValidate_anchor_map_found_invalid ( t * testing . T ) {
// anchor not present in resource
rawPolicy := [ ] byte ( ` {
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 15:12:33 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "policy-secaas-k8s"
} ,
"spec" : {
"rules" : [
{
"name" : "pod rule 2" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "pod: validate run as non root user" ,
"pattern" : {
"spec" : {
2019-10-01 13:08:34 -07:00
"=(securityContext)" : {
2019-09-25 15:12:33 -07:00
"runAsNonRoot" : true
}
}
}
}
}
]
}
} ` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "v1"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx" ,
"image" : "nginx"
}
] ,
"securityContext" : {
"runAsNonRoot" : false
}
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 15:12:33 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-12-04 18:04:42 -08:00
msgs := [ ] string { "Validation error: pod: validate run as non root user; Validation rule 'pod rule 2' failed at path '/spec/securityContext/runAsNonRoot/'" }
2019-09-25 15:12:33 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , ! er . IsSuccesful ( ) )
}
2019-09-25 21:01:45 -07:00
func TestValidate_AnchorList_pass ( t * testing . T ) {
// anchor not present in resource
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 21:01:45 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "policy-secaas-k8s"
} ,
"spec" : {
"rules" : [
{
"name" : "pod image rule" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"pattern" : {
"spec" : {
2019-10-01 13:08:34 -07:00
"=(containers)" : [
2019-09-25 21:01:45 -07:00
{
"name" : "nginx"
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "v1"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx"
} ,
{
"name" : "nginx"
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 21:01:45 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-11-04 20:15:44 -08:00
msgs := [ ] string { "Validation rule 'pod image rule' succeeded." }
2019-09-25 21:01:45 -07:00
2019-10-01 12:35:14 -07:00
for index , r := range er . PolicyResponse . Rules {
t . Log ( r . Message )
assert . Equal ( t , r . Message , msgs [ index ] )
}
2019-09-26 11:00:30 -07:00
assert . Assert ( t , er . IsSuccesful ( ) )
2019-09-25 21:01:45 -07:00
}
func TestValidate_AnchorList_fail ( t * testing . T ) {
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 21:01:45 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "policy-secaas-k8s"
} ,
"spec" : {
"rules" : [
{
"name" : "pod image rule" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"pattern" : {
"spec" : {
2019-10-01 13:08:34 -07:00
"=(containers)" : [
2019-09-25 21:01:45 -07:00
{
"name" : "nginx"
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "v1"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx"
} ,
{
"name" : "busy"
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 21:01:45 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-09-26 11:00:30 -07:00
// msgs := []string{"Validation rule 'pod image rule' failed at '/spec/containers/1/name/' for resource Pod//myapp-pod."}
// for index, r := range er.PolicyResponse.Rules {
2019-10-01 12:35:14 -07:00
// // t.Log(r.Message)
2019-09-26 11:00:30 -07:00
// assert.Equal(t, r.Message, msgs[index])
// }
2019-09-25 21:01:45 -07:00
assert . Assert ( t , ! er . IsSuccesful ( ) )
}
func TestValidate_existenceAnchor_fail ( t * testing . T ) {
// anchor not present in resource
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 21:01:45 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "policy-secaas-k8s"
} ,
"spec" : {
"rules" : [
{
"name" : "pod image rule" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"pattern" : {
"spec" : {
"^(containers)" : [
{
"name" : "nginx"
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "v1"
}
} ,
"spec" : {
"containers" : [
{
"name" : "busy1"
} ,
{
"name" : "busy"
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 21:01:45 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-10-01 12:35:14 -07:00
// msgs := []string{"Validation rule 'pod image rule' failed at '/spec/containers/' for resource Pod//myapp-pod."}
2019-09-25 21:01:45 -07:00
2019-09-26 11:00:30 -07:00
// for index, r := range er.PolicyResponse.Rules {
2019-10-01 12:35:14 -07:00
// t.Log(r.Message)
2019-09-26 11:00:30 -07:00
// assert.Equal(t, r.Message, msgs[index])
// }
2019-09-25 21:01:45 -07:00
assert . Assert ( t , ! er . IsSuccesful ( ) )
}
func TestValidate_existenceAnchor_pass ( t * testing . T ) {
// anchor not present in resource
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-09-25 21:01:45 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "policy-secaas-k8s"
} ,
"spec" : {
"rules" : [
{
"name" : "pod image rule" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"pattern" : {
"spec" : {
"^(containers)" : [
{
"name" : "nginx"
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "myapp-pod" ,
"labels" : {
"app" : "v1"
}
} ,
"spec" : {
"containers" : [
{
"name" : "nginx"
} ,
{
"name" : "busy"
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-09-25 21:01:45 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-11-04 20:15:44 -08:00
msgs := [ ] string { "Validation rule 'pod image rule' succeeded." }
2019-09-25 21:01:45 -07:00
2019-10-01 12:35:14 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
2019-09-26 11:00:30 -07:00
assert . Assert ( t , er . IsSuccesful ( ) )
2019-09-25 21:01:45 -07:00
}
2019-10-10 17:34:20 -07:00
func TestValidate_negationAnchor_deny ( t * testing . T ) {
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-10-10 17:34:20 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "validate-host-path"
} ,
"spec" : {
"rules" : [
{
"name" : "validate-host-path" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "Host path is not allowed" ,
"pattern" : {
"spec" : {
"volumes" : [
{
"name" : "*" ,
"X(hostPath)" : null
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "image-with-hostpath" ,
"labels" : {
"app.type" : "prod" ,
"namespace" : "my-namespace"
}
} ,
"spec" : {
"containers" : [
{
"name" : "image-with-hostpath" ,
"image" : "docker.io/nautiker/curl" ,
"volumeMounts" : [
{
"name" : "var-lib-etcd" ,
"mountPath" : "/var/lib"
}
]
}
] ,
"volumes" : [
{
"name" : "var-lib-etcd" ,
"hostPath" : {
"path" : "/var/lib1"
}
}
]
}
} ` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-10-10 17:34:20 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-12-04 18:04:42 -08:00
msgs := [ ] string { "Validation error: Host path is not allowed; Validation rule 'validate-host-path' failed at path '/spec/volumes/0/hostPath/'" }
2019-10-10 17:34:20 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , ! er . IsSuccesful ( ) )
}
func TestValidate_negationAnchor_pass ( t * testing . T ) {
rawPolicy := [ ] byte ( `
{
2019-11-13 13:56:07 -08:00
"apiVersion" : "kyverno.io/v1" ,
2019-10-10 17:34:20 -07:00
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "validate-host-path"
} ,
"spec" : {
"rules" : [
{
"name" : "validate-host-path" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"message" : "Host path is not allowed" ,
"pattern" : {
"spec" : {
"volumes" : [
{
"name" : "*" ,
"X(hostPath)" : null
}
]
}
}
}
}
]
}
}
` )
rawResource := [ ] byte ( `
{
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "image-with-hostpath" ,
"labels" : {
"app.type" : "prod" ,
"namespace" : "my-namespace"
}
} ,
"spec" : {
"containers" : [
{
"name" : "image-with-hostpath" ,
"image" : "docker.io/nautiker/curl" ,
"volumeMounts" : [
{
"name" : "var-lib-etcd" ,
"mountPath" : "/var/lib"
}
]
}
] ,
"volumes" : [
{
"name" : "var-lib-etcd" ,
"emptyDir" : { }
}
]
}
}
` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( rawPolicy , & policy )
2020-01-07 17:06:17 -08:00
resourceUnstructured , err := utils . ConvertToUnstructured ( rawResource )
2019-10-10 17:34:20 -07:00
assert . NilError ( t , err )
2019-11-13 13:13:07 -08:00
er := Validate ( PolicyContext { Policy : policy , NewResource : * resourceUnstructured } )
2019-11-04 20:15:44 -08:00
msgs := [ ] string { "Validation rule 'validate-host-path' succeeded." }
2019-10-10 17:34:20 -07:00
for index , r := range er . PolicyResponse . Rules {
assert . Equal ( t , r . Message , msgs [ index ] )
}
assert . Assert ( t , er . IsSuccesful ( ) )
}
2020-01-09 17:44:11 -08:00
func Test_VariableSubstitutionPathNotExistInPattern ( t * testing . T ) {
resourceRaw := [ ] byte ( ` {
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "check-root-user"
} ,
"spec" : {
"containers" : [
{
"name" : "check-root-user-a" ,
"image" : "nginxinc/nginx-unprivileged" ,
"securityContext" : {
"runAsNonRoot" : true
}
}
]
}
} ` )
policyraw := [ ] byte ( ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
2020-01-24 12:05:53 -08:00
"name" : "substitute-variable"
2020-01-09 17:44:11 -08:00
} ,
"spec" : {
"rules" : [
{
"name" : "test-path-not-exist" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"validate" : {
"pattern" : {
"spec" : {
"containers" : [
{
"name" : "{{request.object.metadata.name1}}*"
}
]
}
}
}
}
]
}
} ` )
var policy kyverno . ClusterPolicy
json . Unmarshal ( policyraw , & policy )
resourceUnstructured , err := utils . ConvertToUnstructured ( resourceRaw )
assert . NilError ( t , err )
ctx := context . NewContext ( )
ctx . AddResource ( resourceRaw )
policyContext := PolicyContext {
Policy : policy ,
Context : ctx ,
NewResource : * resourceUnstructured }
er := Validate ( policyContext )
2020-02-14 11:59:28 -08:00
assert . Assert ( t , ! er . PolicyResponse . Rules [ 0 ] . Success )
assert . Equal ( t , er . PolicyResponse . Rules [ 0 ] . Message , "Validation error: ; Validation rule 'test-path-not-exist' failed. 'variable(s) not found or has nil values: [/spec/containers/0/name/{{request.object.metadata.name1}}]'" )
2020-01-09 17:44:11 -08:00
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_OnePatternStatisfies ( t * testing . T ) {
resourceRaw := [ ] byte ( ` {
"apiVersion" : "v1" ,
"kind" : "Deployment" ,
"metadata" : {
"name" : "test"
} ,
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "test-pod" ,
"image" : "nginxinc/nginx-unprivileged"
}
]
}
}
}
} ` )
policyraw := [ ] byte ( ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
2020-01-24 12:05:53 -08:00
"name" : "substitute-variable"
2020-01-09 17:44:11 -08:00
} ,
"spec" : {
"rules" : [
{
"name" : "test-path-not-exist" ,
"match" : {
"resources" : {
"kinds" : [
"Deployment"
]
}
} ,
"validate" : {
"anyPattern" : [
{
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "{{request.object.metadata.name1}}*"
}
]
}
}
}
} ,
{
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "{{request.object.metadata.name}}*"
}
]
}
}
}
}
]
}
}
]
}
} ` )
var policy kyverno . ClusterPolicy
assert . NilError ( t , json . Unmarshal ( policyraw , & policy ) )
resourceUnstructured , err := utils . ConvertToUnstructured ( resourceRaw )
assert . NilError ( t , err )
ctx := context . NewContext ( )
ctx . AddResource ( resourceRaw )
policyContext := PolicyContext {
Policy : policy ,
Context : ctx ,
NewResource : * resourceUnstructured }
er := Validate ( policyContext )
2020-02-14 11:59:28 -08:00
assert . Assert ( t , er . PolicyResponse . Rules [ 0 ] . Success )
assert . Equal ( t , er . PolicyResponse . Rules [ 0 ] . Message , "Validation rule 'test-path-not-exist' anyPattern[1] succeeded." )
2020-01-09 17:44:11 -08:00
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathNotPresent ( t * testing . T ) {
resourceRaw := [ ] byte ( ` {
"apiVersion" : "v1" ,
"kind" : "Deployment" ,
"metadata" : {
"name" : "test"
} ,
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "test-pod" ,
"image" : "nginxinc/nginx-unprivileged"
}
]
}
}
}
} ` )
policyraw := [ ] byte ( ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
2020-01-24 12:05:53 -08:00
"name" : "substitute-variable"
2020-01-09 17:44:11 -08:00
} ,
"spec" : {
"rules" : [
{
"name" : "test-path-not-exist" ,
"match" : {
"resources" : {
"kinds" : [
"Deployment"
]
}
} ,
"validate" : {
"anyPattern" : [
{
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "{{request.object.metadata.name1}}*"
}
]
}
}
}
} ,
{
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "{{request.object.metadata.name2}}*"
}
]
}
}
}
}
]
}
}
]
}
} ` )
var policy kyverno . ClusterPolicy
assert . NilError ( t , json . Unmarshal ( policyraw , & policy ) )
resourceUnstructured , err := utils . ConvertToUnstructured ( resourceRaw )
assert . NilError ( t , err )
ctx := context . NewContext ( )
ctx . AddResource ( resourceRaw )
policyContext := PolicyContext {
Policy : policy ,
Context : ctx ,
NewResource : * resourceUnstructured }
er := Validate ( policyContext )
2020-02-14 11:59:28 -08:00
assert . Assert ( t , ! er . PolicyResponse . Rules [ 0 ] . Success )
assert . Equal ( t , er . PolicyResponse . Rules [ 0 ] . Message , "Subsitutions failed at paths: [variable(s) not found or has nil values: [/spec/template/spec/containers/0/name/{{request.object.metadata.name1}}] variable(s) not found or has nil values: [/spec/template/spec/containers/0/name/{{request.object.metadata.name2}}]]" )
2020-01-09 17:44:11 -08:00
}
func Test_VariableSubstitutionPathNotExistInAnyPattern_AllPathPresent_NonePatternSatisfy ( t * testing . T ) {
resourceRaw := [ ] byte ( ` {
"apiVersion" : "v1" ,
"kind" : "Deployment" ,
"metadata" : {
"name" : "test"
} ,
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "pod-test-pod" ,
"image" : "nginxinc/nginx-unprivileged"
}
]
}
}
}
} ` )
policyraw := [ ] byte ( ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
2020-01-24 12:05:53 -08:00
"name" : "substitute-variable"
2020-01-09 17:44:11 -08:00
} ,
"spec" : {
"rules" : [
{
"name" : "test-path-not-exist" ,
"match" : {
"resources" : {
"kinds" : [
"Deployment"
]
}
} ,
"validate" : {
"anyPattern" : [
{
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "{{request.object.metadata.name}}*"
}
]
}
}
}
} ,
{
"spec" : {
"template" : {
"spec" : {
"containers" : [
{
"name" : "{{request.object.metadata.name}}*"
}
]
}
}
}
}
]
}
}
]
}
} ` )
var policy kyverno . ClusterPolicy
assert . NilError ( t , json . Unmarshal ( policyraw , & policy ) )
resourceUnstructured , err := utils . ConvertToUnstructured ( resourceRaw )
assert . NilError ( t , err )
ctx := context . NewContext ( )
ctx . AddResource ( resourceRaw )
policyContext := PolicyContext {
Policy : policy ,
Context : ctx ,
NewResource : * resourceUnstructured }
er := Validate ( policyContext )
2020-02-14 11:59:28 -08:00
// expectedMsg := "Validation error: ; Validation rule test-path-not-exist anyPattern[0] failed at path /spec/template/spec/containers/0/name/. Validation rule test-path-not-exist anyPattern[1] failed at path /spec/template/spec/containers/0/name/."
assert . Assert ( t , ! er . PolicyResponse . Rules [ 0 ] . Success )
assert . Equal ( t , er . PolicyResponse . Rules [ 0 ] . Message , "Validation rule 'test-path-not-exist' failed. [anyPattern[0] failed; Validation rule failed at '/spec/template/spec/containers/0/name/' to validate value 'pod-test-pod' with pattern 'test*' anyPattern[1] failed; Validation rule failed at '/spec/template/spec/containers/0/name/' to validate value 'pod-test-pod' with pattern 'test*']" )
2020-01-09 17:44:11 -08:00
}