2021-10-06 05:42:42 +00:00
package engine
import (
2022-12-09 13:45:11 +00:00
"context"
2021-10-06 05:42:42 +00:00
"encoding/json"
2022-04-27 15:09:52 +00:00
"fmt"
2022-04-19 15:35:12 +00:00
"strings"
2021-10-29 10:24:26 +00:00
"testing"
2023-08-30 07:26:40 +00:00
"time"
2021-10-29 10:24:26 +00:00
2023-02-09 15:15:51 +00:00
"github.com/go-logr/logr"
2023-08-02 14:02:21 +00:00
"github.com/kyverno/kyverno/api/kyverno"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
2023-01-03 12:02:15 +00:00
"github.com/kyverno/kyverno/pkg/config"
2021-10-06 05:42:42 +00:00
"github.com/kyverno/kyverno/pkg/cosign"
2023-06-14 10:06:52 +00:00
"github.com/kyverno/kyverno/pkg/engine/adapters"
2023-01-30 11:41:09 +00:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
2022-12-09 13:45:11 +00:00
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
2022-12-02 13:59:51 +00:00
"github.com/kyverno/kyverno/pkg/engine/context/resolvers"
2023-06-16 13:37:08 +00:00
"github.com/kyverno/kyverno/pkg/engine/factories"
2023-02-07 16:51:25 +00:00
"github.com/kyverno/kyverno/pkg/engine/internal"
2023-04-13 11:29:40 +00:00
"github.com/kyverno/kyverno/pkg/engine/jmespath"
2023-05-13 08:56:54 +00:00
"github.com/kyverno/kyverno/pkg/engine/mutate/patch"
2023-03-24 16:24:00 +00:00
"github.com/kyverno/kyverno/pkg/engine/policycontext"
2023-03-27 15:11:27 +00:00
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
2023-08-06 19:54:52 +00:00
"github.com/kyverno/kyverno/pkg/imageverifycache"
2023-01-03 12:02:15 +00:00
"github.com/kyverno/kyverno/pkg/registryclient"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
2023-06-08 10:23:20 +00:00
"gomodules.xyz/jsonpatch/v2"
2021-10-06 05:42:42 +00:00
"gotest.tools/assert"
2023-01-03 12:02:15 +00:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
kubefake "k8s.io/client-go/kubernetes/fake"
2021-10-06 05:42:42 +00:00
)
2022-04-19 15:35:12 +00:00
var testPolicyGood = ` {
2021-10-06 05:42:42 +00:00
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "attest"
} ,
"spec" : {
"rules" : [
{
"name" : "attest" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"verifyImages" : [
{
"image" : "*" ,
"key" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHMmDjK65krAyDaGaeyWNzgvIu155JI50B2vezCw8+3CVeE0lJTL5dbL3OP98Za0oAEBJcOxky8Riy/XcmfKZbw==\n-----END PUBLIC KEY-----" ,
"attestations" : [
{
"predicateType" : "https://example.com/CodeReview/v1" ,
2022-12-16 08:44:49 +00:00
"attestors" : [
{
"entries" : [
{
"keys" : {
2023-08-15 14:25:55 +00:00
"publicKeys" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHMmDjK65krAyDaGaeyWNzgvIu155JI50B2vezCw8+3CVeE0lJTL5dbL3OP98Za0oAEBJcOxky8Riy/XcmfKZbw==\n-----END PUBLIC KEY-----" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
2023-08-30 06:39:49 +00:00
} ,
"ctlog" : {
"ignoreSCT" : true
2023-08-15 14:25:55 +00:00
}
2022-12-16 08:44:49 +00:00
}
}
]
}
] ,
2021-10-06 05:42:42 +00:00
"conditions" : [
{
"all" : [
{
"key" : "{{ repo.uri }}" ,
"operator" : "Equals" ,
"value" : "https://github.com/example/my-project"
2023-01-02 17:14:40 +00:00
} ,
2021-10-06 05:42:42 +00:00
{
"key" : "{{ repo.branch }}" ,
"operator" : "Equals" ,
"value" : "main"
}
]
}
]
}
]
}
]
}
]
}
} `
2022-04-19 15:35:12 +00:00
var testPolicyBad = ` {
2021-10-06 05:42:42 +00:00
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "attest"
} ,
"spec" : {
"rules" : [
{
"name" : "attest" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"verifyImages" : [
{
"image" : "*" ,
"key" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHMmDjK65krAyDaGaeyWNzgvIu155JI50B2vezCw8+3CVeE0lJTL5dbL3OP98Za0oAEBJcOxky8Riy/XcmfKZbw==\n-----END PUBLIC KEY-----" ,
"attestations" : [
{
"predicateType" : "https://example.com/CodeReview/v1" ,
"conditions" : [
{
"all" : [
{
"key" : "{{ repo.uri }}" ,
"operator" : "Equals" ,
"value" : "https://github.com/example/my-project"
2023-01-02 17:14:40 +00:00
} ,
2021-10-06 05:42:42 +00:00
{
"key" : "{{ repo.branch }}" ,
"operator" : "Equals" ,
"value" : "prod"
}
]
}
]
}
]
}
]
}
]
}
2023-09-20 12:03:58 +00:00
}
`
2021-10-06 05:42:42 +00:00
2022-04-19 15:35:12 +00:00
var testResource = ` {
2021-10-06 05:42:42 +00:00
"apiVersion" : "v1" ,
"kind" : "Pod" ,
2022-04-27 15:09:52 +00:00
"metadata" : {
"name" : "test" ,
"annotations" : { }
} ,
2021-10-06 05:42:42 +00:00
"spec" : {
"containers" : [
{
"name" : "pause2" ,
"image" : "ghcr.io/jimbugwadia/pause2"
}
]
}
} `
2023-09-20 12:03:58 +00:00
var cosignTestResource = ` {
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"name" : "test" ,
"annotations" : { }
} ,
"spec" : {
"containers" : [
{
"name" : "pause2" ,
"image" : "ghcr.io/kyverno/test-verify-image:signed"
}
]
}
} `
var cosignTestPolicy = ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image" ,
"annotations" : {
"pod-policies.kyverno.io/autogen-controllers" : "none"
}
} ,
"spec" : {
"validationFailureAction" : "enforce" ,
"background" : false ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "check-signature" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"verifyImages" : [
{
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image:*"
] ,
2024-08-19 14:26:07 +00:00
"useCache" : true ,
2023-09-20 12:03:58 +00:00
"attestors" : [
{
"entries" : [
{
"keys" : {
"publicKeys" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM\n5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==\n-----END PUBLIC KEY-----" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
} ,
"ctlog" : {
"ignoreSCT" : true
}
}
}
]
}
]
}
]
}
]
}
} `
var cosignTestPolicyUpdated = ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image" ,
"annotations" : {
"pod-policies.kyverno.io/autogen-controllers" : "none"
}
} ,
"spec" : {
"validationFailureAction" : "enforce" ,
"background" : false ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "check-signature-updated" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"verifyImages" : [
{
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image:*"
] ,
2024-08-19 14:26:07 +00:00
"useCache" : true ,
2023-09-20 12:03:58 +00:00
"attestors" : [
{
"entries" : [
{
"keys" : {
"publicKeys" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM\n5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==\n-----END PUBLIC KEY-----" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
} ,
"ctlog" : {
"ignoreSCT" : true
}
}
}
]
}
]
}
]
}
]
}
} `
2022-08-12 10:06:14 +00:00
var attestationPayloads = [ ] [ ] byte {
2021-10-06 05:42:42 +00:00
[ ] byte ( ` { "payloadType":"https://example.com/CodeReview/v1","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2V4YW1wbGUuY29tL0NvZGVSZXZpZXcvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiZ2hjci5pby9qaW1idWd3YWRpYS9wYXVzZTIiLCJkaWdlc3QiOnsic2hhMjU2IjoiYjMxYmZiNGQwMjEzZjI1NGQzNjFlMDA3OWRlYWFlYmVmYTRmODJiYTdhYTc2ZWY4MmU5MGI0OTM1YWQ1YjEwNSJ9fV0sInByZWRpY2F0ZSI6eyJhdXRob3IiOiJtYWlsdG86YWxpY2VAZXhhbXBsZS5jb20iLCJyZXBvIjp7ImJyYW5jaCI6Im1haW4iLCJ0eXBlIjoiZ2l0IiwidXJpIjoiaHR0cHM6Ly9naXRodWIuY29tL2V4YW1wbGUvbXktcHJvamVjdCJ9LCJyZXZpZXdlcnMiOlsibWFpbHRvOmJvYkBleGFtcGxlLmNvbSJdfX0=","signatures":[ { "keyid":"","sig":"MEYCIQCrEr+vgPDmNCrqGDE/4z9iMLmCXMXcDlGKtSoiuMTSFgIhAN2riBaGk4accWzVl7ypi1XTRxyrPYHst8DesugPXgOf"}]} ` ) ,
[ ] byte ( ` { "payloadType":"cosign.sigstore.dev/attestation/v1","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJjb3NpZ24uc2lnc3RvcmUuZGV2L2F0dGVzdGF0aW9uL3YxIiwic3ViamVjdCI6W3sibmFtZSI6ImdoY3IuaW8vamltYnVnd2FkaWEvcGF1c2UyIiwiZGlnZXN0Ijp7InNoYTI1NiI6ImIzMWJmYjRkMDIxM2YyNTRkMzYxZTAwNzlkZWFhZWJlZmE0ZjgyYmE3YWE3NmVmODJlOTBiNDkzNWFkNWIxMDUifX1dLCJwcmVkaWNhdGUiOnsiRGF0YSI6ImhlbGxvIVxuIiwiVGltZXN0YW1wIjoiMjAyMS0xMC0wNVQwNToxODoxMVoifX0=","signatures":[ { "keyid":"","sig":"MEQCIF5r9lf55rnYNPByZ9v6bortww694UEPvmyBIelIDYbIAiBNTGX4V64Oj6jZVRpkJQRxdzKUPYqC5GZTb4oS6eQ6aQ=="}]} ` ) ,
[ ] byte ( ` { "payloadType":"https://example.com/CodeReview/v1","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2V4YW1wbGUuY29tL0NvZGVSZXZpZXcvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoiZ2hjci5pby9qaW1idWd3YWRpYS9wYXVzZTIiLCJkaWdlc3QiOnsic2hhMjU2IjoiYjMxYmZiNGQwMjEzZjI1NGQzNjFlMDA3OWRlYWFlYmVmYTRmODJiYTdhYTc2ZWY4MmU5MGI0OTM1YWQ1YjEwNSJ9fV0sInByZWRpY2F0ZSI6eyJhdXRob3IiOiJtYWlsdG86YWxpY2VAZXhhbXBsZS5jb20iLCJyZXBvIjp7ImJyYW5jaCI6Im1haW4iLCJ0eXBlIjoiZ2l0IiwidXJpIjoiaHR0cHM6Ly9naXRodWIuY29tL2V4YW1wbGUvbXktcHJvamVjdCJ9LCJyZXZpZXdlcnMiOlsibWFpbHRvOmJvYkBleGFtcGxlLmNvbSJdfX0=","signatures":[ { "keyid":"","sig":"MEUCIEeZbdBEFQzWqiMhB+SJgM6yFppUuQSKrpOIX1mxLDmRAiEA8pXqFq0GVc9LKhPzrnJRZhSruDNiKbiLHG5x7ETFyY8="}]} ` ) ,
}
2022-08-12 10:06:14 +00:00
var signaturePayloads = [ ] [ ] byte {
[ ] byte ( ` { "critical": { "identity": { "docker-reference":"ghcr.io/kyverno/test-verify-image"},"image": { "docker-manifest-digest":"sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105"},"type":"cosign container image signature"},"optional":null} ` ) ,
}
2023-04-04 15:07:43 +00:00
var (
cfg = config . NewDefaultConfiguration ( false )
metricsCfg = config . NewDefaultMetricsConfiguration ( )
2023-04-13 11:29:40 +00:00
jp = jmespath . New ( cfg )
2023-04-04 15:07:43 +00:00
)
2023-01-02 17:14:40 +00:00
2023-02-02 10:58:34 +00:00
func testVerifyAndPatchImages (
2023-01-31 14:30:40 +00:00
ctx context . Context ,
rclient registryclient . Client ,
2023-02-03 05:01:11 +00:00
cmResolver engineapi . ConfigmapResolver ,
2023-01-31 15:28:48 +00:00
pContext engineapi . PolicyContext ,
2023-01-31 14:30:40 +00:00
cfg config . Configuration ,
2023-03-23 12:58:52 +00:00
) ( engineapi . EngineResponse , engineapi . ImageVerificationMetadata ) {
2023-02-06 12:49:04 +00:00
e := NewEngine (
cfg ,
2023-04-04 15:07:43 +00:00
metricsCfg ,
2023-04-13 11:29:40 +00:00
jp ,
2023-02-07 15:09:15 +00:00
nil ,
2023-06-16 13:37:08 +00:00
factories . DefaultRegistryClientFactory ( adapters . RegistryClient ( rclient ) , nil ) ,
2023-08-06 19:54:52 +00:00
imageverifycache . DisabledImageVerifyCache ( ) ,
2023-06-16 13:37:08 +00:00
factories . DefaultContextLoaderFactory ( cmResolver ) ,
2023-02-06 05:49:47 +00:00
nil ,
2023-02-06 12:49:04 +00:00
)
return e . VerifyAndPatchImages (
ctx ,
2023-01-31 14:30:40 +00:00
pContext ,
)
}
2022-04-19 15:35:12 +00:00
func Test_CosignMockAttest ( t * testing . T ) {
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , testPolicyGood , testResource , "" )
2022-08-12 10:06:14 +00:00
err := cosign . SetMock ( "ghcr.io/jimbugwadia/pause2:latest" , attestationPayloads )
2023-09-20 12:03:58 +00:00
defer cosign . ClearMock ( )
2021-10-06 05:42:42 +00:00
assert . NilError ( t , err )
2023-02-03 05:01:11 +00:00
er , ivm := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2021-10-06 05:42:42 +00:00
assert . Equal ( t , len ( er . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , er . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass ,
2022-12-01 22:09:44 +00:00
fmt . Sprintf ( "expected: %v, got: %v, failure: %v" ,
2023-04-05 10:35:38 +00:00
engineapi . RuleStatusPass , er . PolicyResponse . Rules [ 0 ] . Status ( ) , er . PolicyResponse . Rules [ 0 ] . Message ( ) ) )
2022-05-05 21:06:18 +00:00
assert . Equal ( t , ivm . IsEmpty ( ) , false )
2023-02-02 10:58:34 +00:00
assert . Equal ( t , ivm . IsVerified ( "ghcr.io/jimbugwadia/pause2:latest" ) , true )
2021-10-06 05:42:42 +00:00
}
2022-04-19 15:35:12 +00:00
func Test_CosignMockAttest_fail ( t * testing . T ) {
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , testPolicyBad , testResource , "" )
2022-08-12 10:06:14 +00:00
err := cosign . SetMock ( "ghcr.io/jimbugwadia/pause2:latest" , attestationPayloads )
2023-09-20 12:03:58 +00:00
defer cosign . ClearMock ( )
2021-10-06 05:42:42 +00:00
assert . NilError ( t , err )
2023-02-03 05:01:11 +00:00
er , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2021-10-06 05:42:42 +00:00
assert . Equal ( t , len ( er . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , er . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusFail )
2021-10-06 05:42:42 +00:00
}
2022-04-27 15:09:52 +00:00
func buildContext ( t * testing . T , policy , resource string , oldResource string ) * PolicyContext {
2023-08-02 14:02:21 +00:00
var cpol kyvernov1 . ClusterPolicy
2022-04-27 15:09:52 +00:00
err := json . Unmarshal ( [ ] byte ( policy ) , & cpol )
assert . NilError ( t , err )
2021-10-06 05:42:42 +00:00
2023-01-03 12:02:15 +00:00
resourceUnstructured , err := kubeutils . BytesToUnstructured ( [ ] byte ( resource ) )
2021-10-06 05:42:42 +00:00
assert . NilError ( t , err )
2022-04-27 15:09:52 +00:00
2023-05-12 14:14:48 +00:00
policyContext , err := policycontext . NewPolicyContext (
jp ,
* resourceUnstructured ,
2023-08-02 14:02:21 +00:00
kyvernov1 . Create ,
2023-05-12 14:14:48 +00:00
nil ,
cfg ,
)
2022-04-27 15:09:52 +00:00
assert . NilError ( t , err )
2021-10-06 05:42:42 +00:00
2023-05-12 14:14:48 +00:00
policyContext = policyContext .
2023-03-24 16:24:00 +00:00
WithPolicy ( & cpol ) .
WithNewResource ( * resourceUnstructured )
2022-04-27 15:09:52 +00:00
if oldResource != "" {
2023-01-03 12:02:15 +00:00
oldResourceUnstructured , err := kubeutils . BytesToUnstructured ( [ ] byte ( oldResource ) )
2022-04-27 15:09:52 +00:00
assert . NilError ( t , err )
2023-05-12 14:14:48 +00:00
err = enginecontext . AddOldResource ( policyContext . JSONContext ( ) , [ ] byte ( oldResource ) )
2022-04-27 15:09:52 +00:00
assert . NilError ( t , err )
2023-03-24 16:24:00 +00:00
policyContext = policyContext . WithOldResource ( * oldResourceUnstructured )
2022-04-27 15:09:52 +00:00
}
2021-10-06 05:42:42 +00:00
return policyContext
}
2022-04-19 15:35:12 +00:00
var testSampleSingleKeyPolicy = `
{
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image" ,
"annotations" : {
"pod-policies.kyverno.io/autogen-controllers" : "none"
}
} ,
"spec" : {
"validationFailureAction" : "enforce" ,
"background" : false ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "check-signature" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"verifyImages" : [
{
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image:*"
] ,
"attestors" : [
{
"entries" : [
{
2022-05-06 04:57:20 +00:00
"keys" : {
2023-08-15 14:25:55 +00:00
"publicKeys" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM\n5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==\n-----END PUBLIC KEY-----" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
2023-08-30 06:39:49 +00:00
} ,
"ctlog" : {
"ignoreSCT" : true
2023-08-15 14:25:55 +00:00
}
2022-04-19 15:35:12 +00:00
}
}
]
}
]
}
]
}
]
}
}
`
var testSampleMultipleKeyPolicy = `
{
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image" ,
"annotations" : {
"pod-policies.kyverno.io/autogen-controllers" : "none"
}
} ,
"spec" : {
"validationFailureAction" : "enforce" ,
"background" : false ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "check-signature" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"verifyImages" : [
{
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image:*"
] ,
"attestors" : [
{
"count" : COUNT ,
"entries" : [
{
2022-05-06 04:57:20 +00:00
"keys" : {
2023-08-15 14:25:55 +00:00
"publicKeys" : "KEY1" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
2023-08-30 06:39:49 +00:00
} ,
"ctlog" : {
"ignoreSCT" : true
2023-08-15 14:25:55 +00:00
}
2022-04-19 15:35:12 +00:00
}
} ,
{
2022-05-06 04:57:20 +00:00
"keys" : {
2023-08-15 14:25:55 +00:00
"publicKeys" : "KEY2" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
2023-08-30 06:39:49 +00:00
} ,
"ctlog" : {
"ignoreSCT" : true
2023-08-15 14:25:55 +00:00
}
2022-04-19 15:35:12 +00:00
}
}
]
}
]
}
]
}
]
}
}
`
2022-11-18 08:27:34 +00:00
var testConfigMapMissing = ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"annotations" : {
"pod-policies.kyverno.io/autogen-controllers" : "none"
} ,
"name" : "image-verify-polset"
} ,
"spec" : {
"background" : false ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"context" : [
{
"configMap" : {
"name" : "myconfigmap" ,
"namespace" : "mynamespace"
} ,
"name" : "myconfigmap"
}
] ,
"match" : {
"any" : [
{
"resources" : {
"kinds" : [
"Pod"
]
}
}
]
} ,
"name" : "image-verify-pol1" ,
"verifyImages" : [
{
"imageReferences" : [
"ghcr.io/*"
] ,
"mutateDigest" : false ,
"verifyDigest" : false ,
"attestors" : [
{
"entries" : [
{
"keys" : {
2023-08-15 14:25:55 +00:00
"publicKeys" : "{{myconfigmap.data.configmapkey}}" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
2023-08-30 06:39:49 +00:00
} ,
"ctlog" : {
"ignoreSCT" : true
2023-08-15 14:25:55 +00:00
}
2022-11-18 08:27:34 +00:00
}
}
]
}
]
}
]
}
] ,
"validationFailureAction" : "Audit" ,
"webhookTimeoutSeconds" : 30
}
} `
2022-04-19 15:35:12 +00:00
var testSampleResource = ` {
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : { "name" : "test" } ,
"spec" : {
"containers" : [
{
"name" : "pause2" ,
"image" : "ghcr.io/kyverno/test-verify-image:signed"
}
]
}
} `
2022-11-18 08:27:34 +00:00
var testConfigMapMissingResource = ` {
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"labels" : {
"run" : "test"
} ,
"name" : "test"
} ,
"spec" : {
"containers" : [
{
"image" : "nginx:latest" ,
"name" : "test" ,
"resources" : { }
}
]
}
} `
2022-12-12 15:20:20 +00:00
var (
testVerifyImageKey = ` -----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==\n-----END PUBLIC KEY-----\n `
testOtherKey = ` -----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpNlOGZ323zMlhs4bcKSpAKQvbcWi5ZLRmijm6SqXDy0Fp0z0Eal+BekFnLzs8rUXUaXlhZ3hNudlgFJH+nFNMw==\n-----END PUBLIC KEY-----\n `
)
2022-04-19 15:35:12 +00:00
2023-03-30 15:31:11 +00:00
func Test_NoMatch ( t * testing . T ) {
2022-11-18 08:27:34 +00:00
policyContext := buildContext ( t , testConfigMapMissing , testConfigMapMissingResource , "" )
2023-02-03 05:01:11 +00:00
err , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2023-03-30 15:31:11 +00:00
assert . Equal ( t , len ( err . PolicyResponse . Rules ) , 0 )
2022-11-18 08:27:34 +00:00
}
func Test_ConfigMapMissingFailure ( t * testing . T ) {
ghcrImage := strings . Replace ( testConfigMapMissingResource , "nginx:latest" , "ghcr.io/kyverno/test-verify-image:signed" , - 1 )
policyContext := buildContext ( t , testConfigMapMissing , ghcrImage , "" )
2022-12-02 13:59:51 +00:00
resolver , err := resolvers . NewClientBasedResolver ( kubefake . NewSimpleClientset ( ) )
assert . NilError ( t , err )
2023-02-03 05:01:11 +00:00
resp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , resolver , policyContext , cfg )
2022-12-02 13:59:51 +00:00
assert . Equal ( t , len ( resp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , resp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusError , resp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2022-11-18 08:27:34 +00:00
}
2022-04-19 15:35:12 +00:00
func Test_SignatureGoodSigned ( t * testing . T ) {
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , testSampleSingleKeyPolicy , testSampleResource , "" )
2023-03-24 16:24:00 +00:00
policyContext . Policy ( ) . GetSpec ( ) . Rules [ 0 ] . VerifyImages [ 0 ] . MutateDigest = true
2023-02-03 05:01:11 +00:00
engineResp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-12-16 08:44:49 +00:00
assert . Equal ( t , len ( engineResp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , engineResp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass , engineResp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2023-06-05 16:41:46 +00:00
constainers , found , err := unstructured . NestedSlice ( engineResp . PatchedResource . UnstructuredContent ( ) , "spec" , "containers" )
assert . NilError ( t , err )
assert . Equal ( t , true , found )
image , found , err := unstructured . NestedString ( constainers [ 0 ] . ( map [ string ] interface { } ) , "image" )
assert . NilError ( t , err )
assert . Equal ( t , true , found )
assert . Equal ( t , "ghcr.io/kyverno/test-verify-image:signed@sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105" , image )
2022-04-19 15:35:12 +00:00
}
func Test_SignatureUnsigned ( t * testing . T ) {
unsigned := strings . Replace ( testSampleResource , ":signed" , ":unsigned" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , testSampleSingleKeyPolicy , unsigned , "" )
2023-02-03 05:01:11 +00:00
engineResp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-12-16 08:44:49 +00:00
assert . Equal ( t , len ( engineResp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , engineResp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusFail , engineResp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2022-04-19 15:35:12 +00:00
}
func Test_SignatureWrongKey ( t * testing . T ) {
otherKey := strings . Replace ( testSampleResource , ":signed" , ":signed-by-someone-else" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , testSampleSingleKeyPolicy , otherKey , "" )
2023-02-03 05:01:11 +00:00
engineResp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-12-16 08:44:49 +00:00
assert . Equal ( t , len ( engineResp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , engineResp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusFail , engineResp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2022-04-19 15:35:12 +00:00
}
func Test_SignaturesMultiKey ( t * testing . T ) {
policy := strings . Replace ( testSampleMultipleKeyPolicy , "KEY1" , testVerifyImageKey , - 1 )
policy = strings . Replace ( policy , "KEY2" , testVerifyImageKey , - 1 )
policy = strings . Replace ( policy , "COUNT" , "0" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , policy , testSampleResource , "" )
2023-02-03 05:01:11 +00:00
engineResp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-12-16 08:44:49 +00:00
assert . Equal ( t , len ( engineResp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , engineResp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass , engineResp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2022-04-19 15:35:12 +00:00
}
func Test_SignaturesMultiKeyFail ( t * testing . T ) {
policy := strings . Replace ( testSampleMultipleKeyPolicy , "KEY1" , testVerifyImageKey , - 1 )
policy = strings . Replace ( policy , "COUNT" , "0" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , policy , testSampleResource , "" )
2023-02-03 05:01:11 +00:00
engineResp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-12-16 08:44:49 +00:00
assert . Equal ( t , len ( engineResp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , engineResp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusFail , engineResp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2022-04-19 15:35:12 +00:00
}
func Test_SignaturesMultiKeyOneGoodKey ( t * testing . T ) {
policy := strings . Replace ( testSampleMultipleKeyPolicy , "KEY1" , testVerifyImageKey , - 1 )
policy = strings . Replace ( policy , "KEY2" , testOtherKey , - 1 )
policy = strings . Replace ( policy , "COUNT" , "1" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , policy , testSampleResource , "" )
2023-02-03 05:01:11 +00:00
engineResp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-12-16 08:44:49 +00:00
assert . Equal ( t , len ( engineResp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , engineResp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass , engineResp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2022-04-19 15:35:12 +00:00
}
func Test_SignaturesMultiKeyZeroGoodKey ( t * testing . T ) {
policy := strings . Replace ( testSampleMultipleKeyPolicy , "KEY1" , testOtherKey , - 1 )
policy = strings . Replace ( policy , "KEY2" , testOtherKey , - 1 )
policy = strings . Replace ( policy , "COUNT" , "1" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , policy , testSampleResource , "" )
2023-02-03 05:01:11 +00:00
resp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-07-29 07:02:26 +00:00
assert . Equal ( t , len ( resp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , resp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusFail , resp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2022-07-29 07:02:26 +00:00
}
func Test_RuleSelectorImageVerify ( t * testing . T ) {
policyContext := buildContext ( t , testSampleSingleKeyPolicy , testSampleResource , "" )
2024-05-29 23:29:24 +00:00
rule := newStaticKeyRule ( "match-all" , testOtherKey )
2023-03-24 16:24:00 +00:00
spec := policyContext . Policy ( ) . GetSpec ( )
2022-07-29 07:02:26 +00:00
spec . Rules = append ( spec . Rules , * rule )
2023-08-02 14:02:21 +00:00
applyAll := kyvernov1 . ApplyAll
2022-07-29 07:02:26 +00:00
spec . ApplyRules = & applyAll
2023-02-03 05:01:11 +00:00
resp , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-07-29 07:02:26 +00:00
assert . Equal ( t , len ( resp . PolicyResponse . Rules ) , 2 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , resp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass , resp . PolicyResponse . Rules [ 0 ] . Message ( ) )
assert . Equal ( t , resp . PolicyResponse . Rules [ 1 ] . Status ( ) , engineapi . RuleStatusFail , resp . PolicyResponse . Rules [ 1 ] . Message ( ) )
2022-07-29 07:02:26 +00:00
2023-08-02 14:02:21 +00:00
applyOne := kyvernov1 . ApplyOne
2022-07-29 07:02:26 +00:00
spec . ApplyRules = & applyOne
2023-02-03 05:01:11 +00:00
resp , _ = testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-07-29 07:02:26 +00:00
assert . Equal ( t , len ( resp . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , resp . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass , resp . PolicyResponse . Rules [ 0 ] . Message ( ) )
2022-07-29 07:02:26 +00:00
}
2024-05-29 23:29:24 +00:00
func newStaticKeyRule ( name , key string ) * kyvernov1 . Rule {
2023-08-02 14:02:21 +00:00
return & kyvernov1 . Rule {
2022-07-29 07:02:26 +00:00
Name : name ,
2023-08-02 14:02:21 +00:00
MatchResources : kyvernov1 . MatchResources {
All : kyvernov1 . ResourceFilters {
2022-07-29 07:02:26 +00:00
{
2023-08-02 14:02:21 +00:00
ResourceDescription : kyvernov1 . ResourceDescription {
2022-07-29 07:02:26 +00:00
Kinds : [ ] string { "Pod" } ,
} ,
} ,
} ,
} ,
2023-08-02 14:02:21 +00:00
VerifyImages : [ ] kyvernov1 . ImageVerification {
2022-07-29 07:02:26 +00:00
{
ImageReferences : [ ] string { "*" } ,
2023-08-02 14:02:21 +00:00
Attestors : [ ] kyvernov1 . AttestorSet {
2022-07-29 07:02:26 +00:00
{
2023-08-02 14:02:21 +00:00
Entries : [ ] kyvernov1 . Attestor {
2022-07-29 07:02:26 +00:00
{
2023-08-02 14:02:21 +00:00
Keys : & kyvernov1 . StaticKeyAttestor {
2022-07-29 07:02:26 +00:00
PublicKeys : key ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
}
2022-04-19 15:35:12 +00:00
}
var testNestedAttestorPolicy = `
{
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image-keyless" ,
"annotations" : {
"pod-policies.kyverno.io/autogen-controllers" : "none"
}
} ,
"spec" : {
"validationFailureAction" : "enforce" ,
"background" : false ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "check-image-keyless" ,
"match" : {
"resources" : {
"kinds" : [
"Pod"
]
}
} ,
"verifyImages" : [
{
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image:*"
] ,
"attestors" : [
{
"count" : COUNT ,
"entries" : [
{
2022-05-06 04:57:20 +00:00
"keys" : {
2023-08-15 14:25:55 +00:00
"publicKeys" : "KEY1" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
2023-08-30 06:39:49 +00:00
} ,
"ctlog" : {
"ignoreSCT" : true
2023-08-15 14:25:55 +00:00
}
2022-04-19 15:35:12 +00:00
}
} ,
{
"attestor" : {
"entries" : [
{
2022-05-06 04:57:20 +00:00
"keys" : {
2023-08-15 14:25:55 +00:00
"publicKeys" : "KEY2" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
2023-08-30 06:39:49 +00:00
} ,
"ctlog" : {
"ignoreSCT" : true
2023-08-15 14:25:55 +00:00
}
2022-04-19 15:35:12 +00:00
}
}
]
}
}
]
}
]
}
]
}
]
}
}
`
func Test_NestedAttestors ( t * testing . T ) {
policy := strings . Replace ( testNestedAttestorPolicy , "KEY1" , testVerifyImageKey , - 1 )
policy = strings . Replace ( policy , "KEY2" , testVerifyImageKey , - 1 )
policy = strings . Replace ( policy , "COUNT" , "0" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext := buildContext ( t , policy , testSampleResource , "" )
2023-02-03 05:01:11 +00:00
err , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-04-19 15:35:12 +00:00
assert . Equal ( t , len ( err . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , err . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass )
2022-04-19 15:35:12 +00:00
policy = strings . Replace ( testNestedAttestorPolicy , "KEY1" , testVerifyImageKey , - 1 )
policy = strings . Replace ( policy , "KEY2" , testOtherKey , - 1 )
policy = strings . Replace ( policy , "COUNT" , "0" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext = buildContext ( t , policy , testSampleResource , "" )
2023-02-03 05:01:11 +00:00
err , _ = testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-04-19 15:35:12 +00:00
assert . Equal ( t , len ( err . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , err . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusFail )
2022-04-19 15:35:12 +00:00
policy = strings . Replace ( testNestedAttestorPolicy , "KEY1" , testVerifyImageKey , - 1 )
policy = strings . Replace ( policy , "KEY2" , testOtherKey , - 1 )
policy = strings . Replace ( policy , "COUNT" , "1" , - 1 )
2022-04-27 15:09:52 +00:00
policyContext = buildContext ( t , policy , testSampleResource , "" )
2023-02-03 05:01:11 +00:00
err , _ = testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-04-19 15:35:12 +00:00
assert . Equal ( t , len ( err . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , err . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass )
2022-04-19 15:35:12 +00:00
}
2022-04-22 07:10:02 +00:00
func Test_ExpandKeys ( t * testing . T ) {
2023-02-07 16:51:25 +00:00
as := internal . ExpandStaticKeys ( createStaticKeyAttestorSet ( "" , true , false , false ) )
2022-04-22 07:10:02 +00:00
assert . Equal ( t , 1 , len ( as . Entries ) )
2023-02-07 16:51:25 +00:00
as = internal . ExpandStaticKeys ( createStaticKeyAttestorSet ( testOtherKey , true , false , false ) )
2022-04-22 07:10:02 +00:00
assert . Equal ( t , 1 , len ( as . Entries ) )
2023-02-07 16:51:25 +00:00
as = internal . ExpandStaticKeys ( createStaticKeyAttestorSet ( testOtherKey + testOtherKey + testOtherKey , true , false , false ) )
2022-04-22 07:10:02 +00:00
assert . Equal ( t , 3 , len ( as . Entries ) )
2022-10-14 09:40:46 +00:00
2023-02-07 16:51:25 +00:00
as = internal . ExpandStaticKeys ( createStaticKeyAttestorSet ( "" , false , true , false ) )
2022-10-14 09:40:46 +00:00
assert . Equal ( t , 1 , len ( as . Entries ) )
2023-08-02 14:02:21 +00:00
assert . DeepEqual ( t , & kyvernov1 . SecretReference { Name : "testsecret" , Namespace : "default" } ,
2022-10-14 09:40:46 +00:00
as . Entries [ 0 ] . Keys . Secret )
2023-02-07 16:51:25 +00:00
as = internal . ExpandStaticKeys ( createStaticKeyAttestorSet ( "" , false , false , true ) )
2022-10-14 09:40:46 +00:00
assert . Equal ( t , 1 , len ( as . Entries ) )
assert . DeepEqual ( t , "gcpkms://projects/test_project_id/locations/asia-south1/keyRings/test_key_ring_name/cryptoKeys/test_key_name/versions/1" , as . Entries [ 0 ] . Keys . KMS )
2023-02-07 16:51:25 +00:00
as = internal . ExpandStaticKeys ( ( createStaticKeyAttestorSet ( testOtherKey , true , true , false ) ) )
2022-10-14 09:40:46 +00:00
assert . Equal ( t , 2 , len ( as . Entries ) )
assert . DeepEqual ( t , testOtherKey , as . Entries [ 0 ] . Keys . PublicKeys )
2023-08-02 14:02:21 +00:00
assert . DeepEqual ( t , & kyvernov1 . SecretReference { Name : "testsecret" , Namespace : "default" } , as . Entries [ 1 ] . Keys . Secret )
2022-04-22 07:10:02 +00:00
}
2023-08-02 14:02:21 +00:00
func createStaticKeyAttestorSet ( s string , withPublicKey , withSecret , withKMS bool ) kyvernov1 . AttestorSet {
var entries [ ] kyvernov1 . Attestor
2022-10-14 09:40:46 +00:00
if withPublicKey {
2023-08-02 14:02:21 +00:00
attestor := kyvernov1 . Attestor {
Keys : & kyvernov1 . StaticKeyAttestor {
2022-10-14 09:40:46 +00:00
PublicKeys : s ,
} ,
}
entries = append ( entries , attestor )
}
if withSecret {
2023-08-02 14:02:21 +00:00
attestor := kyvernov1 . Attestor {
Keys : & kyvernov1 . StaticKeyAttestor {
Secret : & kyvernov1 . SecretReference {
2022-10-14 09:40:46 +00:00
Name : "testsecret" ,
Namespace : "default" ,
2022-04-22 07:10:02 +00:00
} ,
} ,
2022-10-14 09:40:46 +00:00
}
entries = append ( entries , attestor )
}
if withKMS {
kmsKey := "gcpkms://projects/test_project_id/locations/asia-south1/keyRings/test_key_ring_name/cryptoKeys/test_key_name/versions/1"
2023-08-02 14:02:21 +00:00
attestor := kyvernov1 . Attestor {
Keys : & kyvernov1 . StaticKeyAttestor {
2022-10-14 09:40:46 +00:00
KMS : kmsKey ,
} ,
}
entries = append ( entries , attestor )
2022-04-22 07:10:02 +00:00
}
2023-08-02 14:02:21 +00:00
return kyvernov1 . AttestorSet { Entries : entries }
2022-04-22 07:10:02 +00:00
}
2022-04-27 15:09:52 +00:00
func Test_ChangedAnnotation ( t * testing . T ) {
2023-08-02 14:02:21 +00:00
annotationKey := kyverno . AnnotationImageVerify
2022-04-27 15:09:52 +00:00
annotationNew := fmt . Sprintf ( "\"annotations\": {\"%s\": \"%s\"}" , annotationKey , "true" )
newResource := strings . ReplaceAll ( testResource , "\"annotations\": {}" , annotationNew )
policyContext := buildContext ( t , testPolicyGood , testResource , testResource )
2022-05-05 21:06:18 +00:00
2023-02-09 15:15:51 +00:00
hasChanged := internal . HasImageVerifiedAnnotationChanged ( policyContext , logr . Discard ( ) )
2022-04-27 15:09:52 +00:00
assert . Equal ( t , hasChanged , false )
policyContext = buildContext ( t , testPolicyGood , newResource , testResource )
2023-02-09 15:15:51 +00:00
hasChanged = internal . HasImageVerifiedAnnotationChanged ( policyContext , logr . Discard ( ) )
2022-04-27 15:09:52 +00:00
assert . Equal ( t , hasChanged , true )
annotationOld := fmt . Sprintf ( "\"annotations\": {\"%s\": \"%s\"}" , annotationKey , "false" )
oldResource := strings . ReplaceAll ( testResource , "\"annotations\": {}" , annotationOld )
policyContext = buildContext ( t , testPolicyGood , newResource , oldResource )
2023-02-09 15:15:51 +00:00
hasChanged = internal . HasImageVerifiedAnnotationChanged ( policyContext , logr . Discard ( ) )
2022-04-27 15:09:52 +00:00
assert . Equal ( t , hasChanged , true )
}
func Test_MarkImageVerified ( t * testing . T ) {
2022-05-05 21:06:18 +00:00
image := "ghcr.io/jimbugwadia/pause2:latest"
policyContext := buildContext ( t , testPolicyGood , testResource , "" )
2022-08-12 10:06:14 +00:00
err := cosign . SetMock ( image , attestationPayloads )
2023-09-20 12:03:58 +00:00
defer cosign . ClearMock ( )
2022-05-05 21:06:18 +00:00
assert . NilError ( t , err )
2022-04-27 15:09:52 +00:00
2023-02-03 05:01:11 +00:00
engineResponse , verifiedImages := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-05-05 21:06:18 +00:00
assert . Equal ( t , len ( engineResponse . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , engineResponse . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass )
2022-04-27 15:09:52 +00:00
2022-05-05 21:06:18 +00:00
assert . Assert ( t , verifiedImages . Data != nil )
assert . Equal ( t , len ( verifiedImages . Data ) , 1 )
2023-02-02 10:58:34 +00:00
assert . Equal ( t , verifiedImages . IsVerified ( image ) , true )
2022-05-01 23:02:49 +00:00
2023-02-09 15:15:51 +00:00
patches , err := verifiedImages . Patches ( false , logr . Discard ( ) )
2022-05-01 23:02:49 +00:00
assert . NilError ( t , err )
2022-05-05 21:06:18 +00:00
assert . Equal ( t , len ( patches ) , 2 )
2022-05-01 23:02:49 +00:00
2022-12-12 15:20:20 +00:00
resource := testApplyPatches ( t , patches )
2022-05-05 21:06:18 +00:00
patchedAnnotations := resource . GetAnnotations ( )
assert . Equal ( t , len ( patchedAnnotations ) , 1 )
2022-04-27 15:09:52 +00:00
2023-08-02 14:02:21 +00:00
json := patchedAnnotations [ kyverno . AnnotationImageVerify ]
2022-05-05 21:06:18 +00:00
assert . Assert ( t , json != "" )
2023-03-27 15:11:27 +00:00
verified , err := engineutils . IsImageVerified ( resource , image , logr . Discard ( ) )
2022-05-05 21:06:18 +00:00
assert . NilError ( t , err )
2024-01-23 12:27:39 +00:00
assert . Equal ( t , verified , engineapi . ImageVerificationPass )
2022-04-27 15:09:52 +00:00
}
2023-05-13 08:56:54 +00:00
func testApplyPatches ( t * testing . T , patches [ ] jsonpatch . JsonPatchOperation ) unstructured . Unstructured {
patchedResource , err := engineutils . ApplyPatches ( [ ] byte ( testResource ) , patch . ConvertPatches ( patches ... ) )
2022-04-27 15:09:52 +00:00
assert . NilError ( t , err )
assert . Assert ( t , patchedResource != nil )
u := unstructured . Unstructured { }
err = u . UnmarshalJSON ( patchedResource )
assert . NilError ( t , err )
return u
}
2022-08-12 10:06:14 +00:00
func Test_ParsePEMDelimited ( t * testing . T ) {
testPEMPolicy := ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "Policy" ,
"metadata" : {
"name" : "check-image"
} ,
"spec" : {
"validationFailureAction" : "enforce" ,
"background" : false ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "check-image" ,
"match" : {
"any" : [
{
"resources" : {
"kinds" : [
"Pod"
]
}
}
]
} ,
"verifyImages" : [
{
"imageReferences" : [
"*"
] ,
"attestors" : [
{
"count" : 1 ,
"entries" : [
{
"keys" : {
2023-08-15 14:25:55 +00:00
"publicKeys" : "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfVMHGmFK4OgVqhy36KZ7a3r4R4/o\nCwaCVvXZV4ZULFbkFZ0IodGqKqcVmgycnoj7d8TpKpAUVNF8kKh90ewH3A==\n-----END PUBLIC KEY-----\n-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0f1W0XigyPFbX8Xq3QmkbL9gDFTf\nRfc8jF7UadBcwKxiyvPSOKZn+igQfXzpNjrwPSZ58JGvF4Fs8BB3fSRP2g==\n-----END PUBLIC KEY-----" ,
"rekor" : {
"url" : "https://rekor.sigstore.dev" ,
"ignoreTlog" : true
2023-08-30 06:39:49 +00:00
} ,
"ctlog" : {
"ignoreSCT" : true
2023-08-15 14:25:55 +00:00
}
2022-08-12 10:06:14 +00:00
}
}
]
}
]
}
]
}
]
}
} `
image := "ghcr.io/jimbugwadia/pause2:latest"
policyContext := buildContext ( t , testPEMPolicy , testResource , "" )
err := cosign . SetMock ( image , signaturePayloads )
2023-09-20 12:03:58 +00:00
defer cosign . ClearMock ( )
2022-08-12 10:06:14 +00:00
assert . NilError ( t , err )
2023-02-03 05:01:11 +00:00
engineResponse , verifiedImages := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
2022-08-12 10:06:14 +00:00
assert . Equal ( t , len ( engineResponse . PolicyResponse . Rules ) , 1 )
2023-04-05 10:35:38 +00:00
assert . Equal ( t , engineResponse . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass )
2022-08-12 10:06:14 +00:00
assert . Assert ( t , verifiedImages . Data != nil )
assert . Equal ( t , len ( verifiedImages . Data ) , 1 )
2023-02-02 10:58:34 +00:00
assert . Equal ( t , verifiedImages . IsVerified ( image ) , true )
2022-08-12 10:06:14 +00:00
}
2023-08-30 07:26:40 +00:00
func testImageVerifyCache (
ivCache imageverifycache . Client ,
ctx context . Context ,
rclient registryclient . Client ,
cmResolver engineapi . ConfigmapResolver ,
pContext engineapi . PolicyContext ,
cfg config . Configuration ,
) ( engineapi . EngineResponse , engineapi . ImageVerificationMetadata ) {
e := NewEngine (
cfg ,
metricsCfg ,
jp ,
nil ,
factories . DefaultRegistryClientFactory ( adapters . RegistryClient ( rclient ) , nil ) ,
ivCache ,
factories . DefaultContextLoaderFactory ( cmResolver ) ,
nil ,
)
return e . VerifyAndPatchImages (
ctx ,
pContext ,
)
}
func errorAssertionUtil ( t * testing . T , image string , ivm engineapi . ImageVerificationMetadata , er engineapi . EngineResponse ) {
assert . Equal ( t , len ( er . PolicyResponse . Rules ) , 1 )
2023-09-20 12:03:58 +00:00
assert . Equal ( t , er . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass , er . PolicyResponse . Rules [ 0 ] . Message ( ) )
2023-08-30 07:26:40 +00:00
assert . Equal ( t , ivm . IsEmpty ( ) , false )
assert . Equal ( t , ivm . IsVerified ( image ) , true )
}
func Test_ImageVerifyCacheCosign ( t * testing . T ) {
opts := [ ] imageverifycache . Option {
imageverifycache . WithCacheEnableFlag ( true ) ,
imageverifycache . WithMaxSize ( 1000 ) ,
imageverifycache . WithTTLDuration ( 24 * time . Hour ) ,
}
imageVerifyCache , err := imageverifycache . New ( opts ... )
assert . NilError ( t , err )
2023-09-20 12:03:58 +00:00
image := "ghcr.io/kyverno/test-verify-image:signed"
policyContext := buildContext ( t , cosignTestPolicy , cosignTestResource , "" )
2023-08-30 07:26:40 +00:00
start := time . Now ( )
er , ivm := testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
firstOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
start = time . Now ( )
er , ivm = testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
secondOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
2023-09-20 12:03:58 +00:00
assert . Check ( t , secondOperationTime < firstOperationTime / 10 , "cache entry is valid, so image verification should be from cache." , firstOperationTime , secondOperationTime )
2023-08-30 07:26:40 +00:00
}
2024-08-19 14:26:07 +00:00
func Test_ImageVerifyCacheDisabled ( t * testing . T ) {
opts := [ ] imageverifycache . Option {
imageverifycache . WithCacheEnableFlag ( false ) ,
imageverifycache . WithMaxSize ( 1000 ) ,
imageverifycache . WithTTLDuration ( 24 * time . Hour ) ,
}
imageVerifyCache , err := imageverifycache . New ( opts ... )
assert . NilError ( t , err )
image := "ghcr.io/kyverno/test-verify-image:signed"
policyContext := buildContext ( t , cosignTestPolicy , cosignTestResource , "" )
start := time . Now ( )
er , ivm := testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
firstOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
start = time . Now ( )
er , ivm = testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
secondOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
assert . Check ( t , secondOperationTime > firstOperationTime / 10 && secondOperationTime < firstOperationTime * 10 , "cache is disabled, so image verification should not be from cache." , firstOperationTime , secondOperationTime )
}
2023-08-30 07:26:40 +00:00
func Test_ImageVerifyCacheExpiredCosign ( t * testing . T ) {
opts := [ ] imageverifycache . Option {
imageverifycache . WithCacheEnableFlag ( true ) ,
imageverifycache . WithMaxSize ( 1000 ) ,
2023-09-21 12:39:54 +00:00
imageverifycache . WithTTLDuration ( 2 * time . Second ) ,
2023-08-30 07:26:40 +00:00
}
imageVerifyCache , err := imageverifycache . New ( opts ... )
assert . NilError ( t , err )
2023-09-20 12:03:58 +00:00
image := "ghcr.io/kyverno/test-verify-image:signed"
policyContext := buildContext ( t , cosignTestPolicy , cosignTestResource , "" )
2023-08-30 07:26:40 +00:00
start := time . Now ( )
er , ivm := testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
firstOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
time . Sleep ( 5 * time . Second )
start = time . Now ( )
er , ivm = testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
secondOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
2023-09-21 12:39:54 +00:00
assert . Check ( t , secondOperationTime > firstOperationTime / 10 && secondOperationTime < firstOperationTime * 10 , "cache entry is expired, so image verification should not be from cache." , firstOperationTime , secondOperationTime )
2023-08-30 07:26:40 +00:00
}
func Test_changePolicyCacheVerificationCosign ( t * testing . T ) {
opts := [ ] imageverifycache . Option {
imageverifycache . WithCacheEnableFlag ( true ) ,
imageverifycache . WithMaxSize ( 1000 ) ,
imageverifycache . WithTTLDuration ( 60 * time . Minute ) ,
}
imageVerifyCache , err := imageverifycache . New ( opts ... )
assert . NilError ( t , err )
2023-09-20 12:03:58 +00:00
image := "ghcr.io/kyverno/test-verify-image:signed"
policyContext := buildContext ( t , cosignTestPolicy , cosignTestResource , "" )
2023-08-30 07:26:40 +00:00
start := time . Now ( )
er , ivm := testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
firstOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
2023-09-20 12:03:58 +00:00
policyContext = buildContext ( t , cosignTestPolicyUpdated , cosignTestResource , "" )
2023-08-30 07:26:40 +00:00
start = time . Now ( )
er , ivm = testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
secondOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
2023-09-21 12:39:54 +00:00
assert . Check ( t , secondOperationTime > firstOperationTime / 10 && secondOperationTime < firstOperationTime * 10 , "cache entry not found, so image verification should not be from cache." , firstOperationTime , secondOperationTime )
2023-08-30 07:26:40 +00:00
}
var verifyImageNotaryPolicy = ` {
"apiVersion" : "kyverno.io/v2beta1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image-notary"
} ,
"spec" : {
"validationFailureAction" : "Enforce" ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "verify-signature-notary" ,
"match" : {
"any" : [
{
"resources" : {
"kinds" : [
"Pod"
]
}
}
]
} ,
"verifyImages" : [
{
"type" : "Notary" ,
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image*"
] ,
2024-08-19 14:26:07 +00:00
"useCache" : true ,
2023-08-30 07:26:40 +00:00
"attestors" : [
{
"count" : 1 ,
"entries" : [
{
"certificates" : {
"cert" : "-----BEGIN CERTIFICATE-----\nMIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG\nTm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx\nMTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0\ndGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+\nb+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL\nhVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m\nIia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0\nVp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f\nETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG\nA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G\nCSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9\nkYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8\nZq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF\nByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ\n5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0\nuOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz\n-----END CERTIFICATE-----"
}
}
]
}
]
}
]
}
]
}
} `
var verifyImageNotaryUpdatedPolicy = ` {
"apiVersion" : "kyverno.io/v2beta1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image-notary"
} ,
"spec" : {
"validationFailureAction" : "Enforce" ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "verify-signature-notary-1" ,
"match" : {
"any" : [
{
"resources" : {
"kinds" : [
"Pod"
]
}
}
]
} ,
"verifyImages" : [
{
"type" : "Notary" ,
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image*"
] ,
2024-08-19 14:26:07 +00:00
"useCache" : true ,
2023-08-30 07:26:40 +00:00
"attestors" : [
{
"count" : 1 ,
"entries" : [
{
"certificates" : {
"cert" : "-----BEGIN CERTIFICATE-----\nMIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG\nTm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx\nMTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0\ndGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+\nb+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL\nhVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m\nIia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0\nVp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f\nETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG\nA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G\nCSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9\nkYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8\nZq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF\nByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ\n5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0\nuOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz\n-----END CERTIFICATE-----"
}
}
]
}
]
}
]
}
]
}
} `
var verifyImageNotaryResource = ` {
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"creationTimestamp" : null ,
"labels" : {
"run" : "test"
} ,
"name" : "test" ,
"namespace" : "default"
} ,
"spec" : {
"containers" : [
{
"image" : "ghcr.io/kyverno/test-verify-image:signed" ,
"name" : "test" ,
"resources" : { }
}
] ,
"dnsPolicy" : "ClusterFirst" ,
"restartPolicy" : "Always"
} ,
"status" : { }
} `
func Test_ImageVerifyCacheNotary ( t * testing . T ) {
opts := [ ] imageverifycache . Option {
imageverifycache . WithCacheEnableFlag ( true ) ,
imageverifycache . WithMaxSize ( 1000 ) ,
imageverifycache . WithTTLDuration ( 24 * time . Hour ) ,
}
imageVerifyCache , err := imageverifycache . New ( opts ... )
assert . NilError ( t , err )
image := "ghcr.io/kyverno/test-verify-image:signed"
policyContext := buildContext ( t , verifyImageNotaryPolicy , verifyImageNotaryResource , "" )
start := time . Now ( )
er , ivm := testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
firstOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
start = time . Now ( )
er , ivm = testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
secondOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
2023-09-20 12:03:58 +00:00
assert . Check ( t , secondOperationTime < firstOperationTime / 10 , "cache entry is valid, so image verification should be from cache." , firstOperationTime , secondOperationTime )
2023-08-30 07:26:40 +00:00
}
func Test_ImageVerifyCacheExpiredNotary ( t * testing . T ) {
opts := [ ] imageverifycache . Option {
imageverifycache . WithCacheEnableFlag ( true ) ,
imageverifycache . WithMaxSize ( 1000 ) ,
2023-09-21 12:39:54 +00:00
imageverifycache . WithTTLDuration ( 2 * time . Second ) ,
2023-08-30 07:26:40 +00:00
}
imageVerifyCache , err := imageverifycache . New ( opts ... )
assert . NilError ( t , err )
image := "ghcr.io/kyverno/test-verify-image:signed"
policyContext := buildContext ( t , verifyImageNotaryPolicy , verifyImageNotaryResource , "" )
start := time . Now ( )
er , ivm := testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
firstOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
2023-09-21 12:39:54 +00:00
2023-08-30 07:26:40 +00:00
time . Sleep ( 5 * time . Second )
start = time . Now ( )
er , ivm = testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
secondOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
2023-09-21 12:39:54 +00:00
assert . Check ( t , secondOperationTime > firstOperationTime / 10 && secondOperationTime < firstOperationTime * 10 , "cache entry is expired, so image verification should not be from cache." , firstOperationTime , secondOperationTime )
2023-08-30 07:26:40 +00:00
}
func Test_changePolicyCacheVerificationNotary ( t * testing . T ) {
opts := [ ] imageverifycache . Option {
imageverifycache . WithCacheEnableFlag ( true ) ,
imageverifycache . WithMaxSize ( 1000 ) ,
imageverifycache . WithTTLDuration ( 60 * time . Minute ) ,
}
imageVerifyCache , err := imageverifycache . New ( opts ... )
assert . NilError ( t , err )
image := "ghcr.io/kyverno/test-verify-image:signed"
policyContext := buildContext ( t , verifyImageNotaryPolicy , verifyImageNotaryResource , "" )
start := time . Now ( )
er , ivm := testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
firstOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
policyContext = buildContext ( t , verifyImageNotaryUpdatedPolicy , verifyImageNotaryResource , "" )
start = time . Now ( )
er , ivm = testImageVerifyCache ( imageVerifyCache , context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContext , cfg )
secondOperationTime := time . Since ( start )
errorAssertionUtil ( t , image , ivm , er )
2023-09-21 12:39:54 +00:00
assert . Check ( t , secondOperationTime > firstOperationTime / 10 && secondOperationTime < firstOperationTime * 10 , "cache entry not found, so image verification should not be from cache." , firstOperationTime , secondOperationTime )
2023-08-30 07:26:40 +00:00
}
2024-01-23 12:27:39 +00:00
var excludeVerifyImageNotaryPolicy = ` {
"apiVersion" : "kyverno.io/v2beta1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image-notary"
} ,
"spec" : {
"validationFailureAction" : "Enforce" ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "verify-signature-notary" ,
"match" : {
"any" : [
{
"resources" : {
"kinds" : [
"Pod"
]
}
}
]
} ,
"verifyImages" : [
{
"type" : "Notary" ,
"imageReferences" : [
"ghcr.io/*"
] ,
"skipImageReferences" : [
"ghcr.io/invalid-user*"
] ,
"attestors" : [
{
"count" : 1 ,
"entries" : [
{
"certificates" : {
"cert" : "-----BEGIN CERTIFICATE-----\nMIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG\nTm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx\nMTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0\ndGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+\nb+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL\nhVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m\nIia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0\nVp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f\nETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG\nA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G\nCSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9\nkYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8\nZq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF\nByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ\n5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0\nuOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz\n-----END CERTIFICATE-----"
}
}
]
}
]
}
]
}
]
}
} `
var excludeVerifyImageNotaryResourcePass = ` {
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"creationTimestamp" : null ,
"labels" : {
"run" : "test"
} ,
"name" : "test" ,
"namespace" : "default"
} ,
"spec" : {
"containers" : [
{
"image" : "ghcr.io/kyverno/test-verify-image:signed" ,
"name" : "test" ,
"resources" : { }
}
] ,
"dnsPolicy" : "ClusterFirst" ,
"restartPolicy" : "Always"
} ,
"status" : { }
} `
var excludeVerifyImageNotaryResourceSkip = ` {
"apiVersion" : "v1" ,
"kind" : "Pod" ,
"metadata" : {
"creationTimestamp" : null ,
"labels" : {
"run" : "test"
} ,
"name" : "testskip" ,
"namespace" : "default"
} ,
"spec" : {
"containers" : [
{
"image" : "ghcr.io/invalid-user/invalid-image:v1" ,
"name" : "test" ,
"resources" : { }
}
] ,
"dnsPolicy" : "ClusterFirst" ,
"restartPolicy" : "Always"
} ,
"status" : { }
} `
func Test_SkipImageReferences ( t * testing . T ) {
policyContextPass := buildContext ( t , excludeVerifyImageNotaryPolicy , excludeVerifyImageNotaryResourcePass , "" )
// Passes as image is included and not excluded
2024-09-05 10:33:37 +00:00
erPass , ivm := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContextPass , cfg )
assert . Equal ( t , len ( erPass . PolicyResponse . Rules ) , 1 )
assert . Equal ( t , erPass . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass ,
fmt . Sprintf ( "expected: %v, got: %v, failure: %v" ,
engineapi . RuleStatusPass , erPass . PolicyResponse . Rules [ 0 ] . Status ( ) , erPass . PolicyResponse . Rules [ 0 ] . Message ( ) ) )
assert . Equal ( t , ivm . IsEmpty ( ) , false )
policyContextSkip := buildContext ( t , excludeVerifyImageNotaryPolicy , excludeVerifyImageNotaryResourceSkip , "" )
// Skipped as image is excluded
erSkip , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContextSkip , cfg )
assert . Equal ( t , len ( erSkip . PolicyResponse . Rules ) , 1 )
assert . Equal ( t , erSkip . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusSkip ,
fmt . Sprintf ( "expected: %v, got: %v, failure: %v" ,
engineapi . RuleStatusPass , erSkip . PolicyResponse . Rules [ 0 ] . Status ( ) , erSkip . PolicyResponse . Rules [ 0 ] . Message ( ) ) )
}
var multipleImageVerificationAttestationPolicyPass = ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image-attestation"
} ,
"spec" : {
"validationFailureAction" : "Enforce" ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "verify-attestation-notary" ,
"match" : {
"any" : [
{
"resources" : {
"kinds" : [
"Pod"
]
}
}
]
} ,
"context" : [
{
"name" : "keys" ,
"configMap" : {
"name" : "keys" ,
"namespace" : "notary-verify-attestation"
}
}
] ,
"verifyImages" : [
{
"type" : "Notary" ,
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image*"
] ,
"attestations" : [
{
"type" : "sbom/cyclone-dx" ,
"name" : "sbom" ,
"attestors" : [
{
"entries" : [
{
"certificates" : {
"cert" : "-----BEGIN CERTIFICATE-----\nMIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG\nTm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx\nMTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0\ndGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+\nb+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL\nhVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m\nIia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0\nVp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f\nETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG\nA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G\nCSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9\nkYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8\nZq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF\nByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ\n5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0\nuOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz\n-----END CERTIFICATE-----"
}
}
]
}
]
} ,
{
"type" : "vulnerability-scan" ,
"name" : "scan" ,
"attestors" : [
{
"entries" : [
{
"certificates" : {
"cert" : "-----BEGIN CERTIFICATE-----\nMIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG\nTm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx\nMTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0\ndGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+\nb+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL\nhVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m\nIia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0\nVp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f\nETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG\nA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G\nCSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9\nkYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8\nZq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF\nByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ\n5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0\nuOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz\n-----END CERTIFICATE-----"
}
}
]
}
]
}
] ,
"validate" : {
"deny" : {
"conditions" : {
"any" : [
{
"key" : "{{ time_after('{{ sbom.metadata.timestamp }}', '{{ scan.descriptor.timestamp }}' ) }}" ,
"operator" : "Equals" ,
"value" : "False"
}
]
}
} ,
"message" : "Sample Validation"
}
}
]
}
]
}
} `
var multipleImageVerificationAttestationPolicyFail = ` {
"apiVersion" : "kyverno.io/v1" ,
"kind" : "ClusterPolicy" ,
"metadata" : {
"name" : "check-image-attestation"
} ,
"spec" : {
"validationFailureAction" : "Enforce" ,
"webhookTimeoutSeconds" : 30 ,
"failurePolicy" : "Fail" ,
"rules" : [
{
"name" : "verify-attestation-notary" ,
"match" : {
"any" : [
{
"resources" : {
"kinds" : [
"Pod"
]
}
}
]
} ,
"context" : [
{
"name" : "keys" ,
"configMap" : {
"name" : "keys" ,
"namespace" : "notary-verify-attestation"
}
}
] ,
"verifyImages" : [
{
"type" : "Notary" ,
"imageReferences" : [
"ghcr.io/kyverno/test-verify-image*"
] ,
"attestations" : [
{
"type" : "sbom/cyclone-dx" ,
"name" : "sbom" ,
"attestors" : [
{
"entries" : [
{
"certificates" : {
"cert" : "-----BEGIN CERTIFICATE-----\nMIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG\nTm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx\nMTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0\ndGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+\nb+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL\nhVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m\nIia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0\nVp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f\nETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG\nA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G\nCSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9\nkYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8\nZq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF\nByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ\n5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0\nuOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz\n-----END CERTIFICATE-----"
}
}
]
}
]
} ,
{
"type" : "vulnerability-scan" ,
"name" : "scan" ,
"attestors" : [
{
"entries" : [
{
"certificates" : {
"cert" : "-----BEGIN CERTIFICATE-----\nMIIDTTCCAjWgAwIBAgIJAPI+zAzn4s0xMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV\nBAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UEBwwHU2VhdHRsZTEPMA0GA1UECgwG\nTm90YXJ5MQ0wCwYDVQQDDAR0ZXN0MB4XDTIzMDUyMjIxMTUxOFoXDTMzMDUxOTIx\nMTUxOFowTDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0\ndGxlMQ8wDQYDVQQKDAZOb3RhcnkxDTALBgNVBAMMBHRlc3QwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQDNhTwv+QMk7jEHufFfIFlBjn2NiJaYPgL4eBS+\nb+o37ve5Zn9nzRppV6kGsa161r9s2KkLXmJrojNy6vo9a6g6RtZ3F6xKiWLUmbAL\nhVTCfYw/2n7xNlVMjyyUpE+7e193PF8HfQrfDFxe2JnX5LHtGe+X9vdvo2l41R6m\nIia04DvpMdG4+da2tKPzXIuLUz/FDb6IODO3+qsqQLwEKmmUee+KX+3yw8I6G1y0\nVp0mnHfsfutlHeG8gazCDlzEsuD4QJ9BKeRf2Vrb0ywqNLkGCbcCWF2H5Q80Iq/f\nETVO9z88R7WheVdEjUB8UrY7ZMLdADM14IPhY2Y+tLaSzEVZAgMBAAGjMjAwMAkG\nA1UdEwQCMAAwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0G\nCSqGSIb3DQEBCwUAA4IBAQBX7x4Ucre8AIUmXZ5PUK/zUBVOrZZzR1YE8w86J4X9\nkYeTtlijf9i2LTZMfGuG0dEVFN4ae3CCpBst+ilhIndnoxTyzP+sNy4RCRQ2Y/k8\nZq235KIh7uucq96PL0qsF9s2RpTKXxyOGdtp9+HO0Ty5txJE2txtLDUIVPK5WNDF\nByCEQNhtHgN6V20b8KU2oLBZ9vyB8V010dQz0NRTDLhkcvJig00535/LUylECYAJ\n5/jn6XKt6UYCQJbVNzBg/YPGc1RF4xdsGVDBben/JXpeGEmkdmXPILTKd9tZ5TC0\nuOKpF5rWAruB5PCIrquamOejpXV9aQA/K2JQDuc0mcKz\n-----END CERTIFICATE-----"
}
}
]
}
]
}
] ,
"validate" : {
"deny" : {
"conditions" : {
"any" : [
{
"key" : "{{ time_after('{{ sbom.metadata.timestamp }}', '{{ scan.descriptor.timestamp }}' ) }}" ,
"operator" : "Equals" ,
"value" : "True"
}
]
}
} ,
"message" : "Sample Validation"
}
}
]
}
]
}
} `
func Test_MultipleImageVerificationAttestationPass ( t * testing . T ) {
policyContextPass := buildContext ( t , multipleImageVerificationAttestationPolicyPass , excludeVerifyImageNotaryResourcePass , "" )
// Passes as image is included and not excluded
erPass , ivm := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContextPass , cfg )
assert . Equal ( t , len ( erPass . PolicyResponse . Rules ) , 1 )
assert . Equal ( t , erPass . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass ,
fmt . Sprintf ( "expected: %v, got: %v, failure: %v" ,
engineapi . RuleStatusPass , erPass . PolicyResponse . Rules [ 0 ] . Status ( ) , erPass . PolicyResponse . Rules [ 0 ] . Message ( ) ) )
assert . Equal ( t , ivm . IsEmpty ( ) , false )
policyContextSkip := buildContext ( t , excludeVerifyImageNotaryPolicy , excludeVerifyImageNotaryResourceSkip , "" )
// Skipped as image is excluded
erSkip , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContextSkip , cfg )
assert . Equal ( t , len ( erSkip . PolicyResponse . Rules ) , 1 )
assert . Equal ( t , erSkip . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusSkip ,
fmt . Sprintf ( "expected: %v, got: %v, failure: %v" ,
engineapi . RuleStatusPass , erSkip . PolicyResponse . Rules [ 0 ] . Status ( ) , erSkip . PolicyResponse . Rules [ 0 ] . Message ( ) ) )
}
func Test_MultipleImageVerificationAttestationFail ( t * testing . T ) {
policyContextPass := buildContext ( t , multipleImageVerificationAttestationPolicyFail , excludeVerifyImageNotaryResourcePass , "" )
// Passes as image is included and not excluded
2024-01-23 12:27:39 +00:00
erPass , ivm := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContextPass , cfg )
assert . Equal ( t , len ( erPass . PolicyResponse . Rules ) , 1 )
assert . Equal ( t , erPass . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusPass ,
fmt . Sprintf ( "expected: %v, got: %v, failure: %v" ,
engineapi . RuleStatusPass , erPass . PolicyResponse . Rules [ 0 ] . Status ( ) , erPass . PolicyResponse . Rules [ 0 ] . Message ( ) ) )
assert . Equal ( t , ivm . IsEmpty ( ) , false )
policyContextSkip := buildContext ( t , excludeVerifyImageNotaryPolicy , excludeVerifyImageNotaryResourceSkip , "" )
// Skipped as image is excluded
erSkip , _ := testVerifyAndPatchImages ( context . TODO ( ) , registryclient . NewOrDie ( ) , nil , policyContextSkip , cfg )
assert . Equal ( t , len ( erSkip . PolicyResponse . Rules ) , 1 )
assert . Equal ( t , erSkip . PolicyResponse . Rules [ 0 ] . Status ( ) , engineapi . RuleStatusSkip ,
fmt . Sprintf ( "expected: %v, got: %v, failure: %v" ,
engineapi . RuleStatusPass , erSkip . PolicyResponse . Rules [ 0 ] . Status ( ) , erSkip . PolicyResponse . Rules [ 0 ] . Message ( ) ) )
}