mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
080a96fed4
* Refactor fuzzing utils and add 3 fuzzers Signed-off-by: AdamKorcz <adam@adalogics.com> * Fix lint issues Signed-off-by: AdamKorcz <adam@adalogics.com> * use latest go-jmespath Signed-off-by: AdamKorcz <adam@adalogics.com> * Check layer size (#8552) * fix excessive logs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * check fetched layer size Signed-off-by: Jim Bugwadia <jim@nirmata.com> * check sig layer size Signed-off-by: Jim Bugwadia <jim@nirmata.com> --------- Signed-off-by: Jim Bugwadia <jim@nirmata.com> Signed-off-by: AdamKorcz <adam@adalogics.com> * fix lint issues Signed-off-by: AdamKorcz <adam@adalogics.com> --------- Signed-off-by: AdamKorcz <adam@adalogics.com> Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Jim Bugwadia <jim@nirmata.com>
284 lines
6.3 KiB
Go
284 lines
6.3 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
|
|
kyvFuzz "github.com/kyverno/kyverno/pkg/utils/fuzz"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
|
|
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
|
|
|
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
|
|
"github.com/kyverno/kyverno/pkg/autogen"
|
|
"github.com/kyverno/kyverno/pkg/config"
|
|
"github.com/kyverno/kyverno/pkg/engine/adapters"
|
|
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
|
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
|
"github.com/kyverno/kyverno/pkg/engine/factories"
|
|
"github.com/kyverno/kyverno/pkg/engine/jmespath"
|
|
"github.com/kyverno/kyverno/pkg/engine/policycontext"
|
|
"github.com/kyverno/kyverno/pkg/imageverifycache"
|
|
"github.com/kyverno/kyverno/pkg/registryclient"
|
|
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
|
)
|
|
|
|
var (
|
|
fuzzCfg = config.NewDefaultConfiguration(false)
|
|
fuzzMetricsCfg = config.NewDefaultMetricsConfiguration()
|
|
fuzzJp = jmespath.New(fuzzCfg)
|
|
|
|
validateContext = context.Background()
|
|
regClient = registryclient.NewOrDie()
|
|
validateEngine = NewEngine(
|
|
fuzzCfg,
|
|
config.NewDefaultMetricsConfiguration(),
|
|
fuzzJp,
|
|
nil,
|
|
factories.DefaultRegistryClientFactory(adapters.RegistryClient(regClient), nil),
|
|
imageverifycache.DisabledImageVerifyCache(),
|
|
factories.DefaultContextLoaderFactory(nil),
|
|
nil,
|
|
"",
|
|
)
|
|
initter sync.Once
|
|
)
|
|
|
|
func buildFuzzContext(ff *fuzz.ConsumeFuzzer) (*PolicyContext, error) {
|
|
cpSpec, err := kyvFuzz.CreatePolicySpec(ff)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cpol := &kyverno.ClusterPolicy{}
|
|
cpol.Spec = cpSpec
|
|
|
|
if len(autogen.ComputeRules(cpol)) == 0 {
|
|
return nil, fmt.Errorf("No rules created")
|
|
}
|
|
|
|
resourceUnstructured, err := kyvFuzz.CreateUnstructuredObject(ff, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
policyContext, err := policycontext.NewPolicyContext(
|
|
fuzzJp,
|
|
*resourceUnstructured,
|
|
kyverno.Create,
|
|
nil,
|
|
fuzzCfg,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
policyContext = policyContext.
|
|
WithPolicy(cpol).
|
|
WithNewResource(*resourceUnstructured)
|
|
|
|
addOldResource, err := ff.GetBool()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if addOldResource {
|
|
oldResourceUnstructured, err := kyvFuzz.CreateUnstructuredObject(ff, "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
oldResource, err := json.Marshal(oldResourceUnstructured)
|
|
if err != nil {
|
|
return policyContext, nil
|
|
}
|
|
|
|
err = enginecontext.AddOldResource(policyContext.JSONContext(), oldResource)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
policyContext = policyContext.WithOldResource(*oldResourceUnstructured)
|
|
}
|
|
|
|
return policyContext, nil
|
|
}
|
|
|
|
/*
|
|
VerifyAndPatchImage
|
|
*/
|
|
func FuzzVerifyImageAndPatchTest(f *testing.F) {
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
ff := fuzz.NewConsumer(data)
|
|
pc, err := buildFuzzContext(ff)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
verifyImageAndPatchEngine := NewEngine(
|
|
fuzzCfg,
|
|
fuzzMetricsCfg,
|
|
fuzzJp,
|
|
nil,
|
|
factories.DefaultRegistryClientFactory(adapters.RegistryClient(registryclient.NewOrDie()), nil),
|
|
imageverifycache.DisabledImageVerifyCache(),
|
|
factories.DefaultContextLoaderFactory(nil),
|
|
nil,
|
|
"",
|
|
)
|
|
|
|
_, _ = verifyImageAndPatchEngine.VerifyAndPatchImages(
|
|
context.Background(),
|
|
pc,
|
|
)
|
|
})
|
|
}
|
|
|
|
func FuzzEngineValidateTest(f *testing.F) {
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
ff := fuzz.NewConsumer(data)
|
|
cpSpec, err := kyvFuzz.CreatePolicySpec(ff)
|
|
if err != nil {
|
|
return
|
|
}
|
|
policy := &kyverno.ClusterPolicy{}
|
|
policy.Spec = cpSpec
|
|
|
|
if len(autogen.ComputeRules(policy)) == 0 {
|
|
return
|
|
}
|
|
|
|
resourceUnstructured, err := kyvFuzz.CreateUnstructuredObject(ff, "")
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
pc, err := NewPolicyContext(fuzzJp, *resourceUnstructured, kyverno.Create, nil, fuzzCfg)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
validateEngine.Validate(
|
|
validateContext,
|
|
pc.WithPolicy(policy),
|
|
)
|
|
})
|
|
}
|
|
|
|
func getPod(ff *fuzz.ConsumeFuzzer) (*corev1.Pod, error) {
|
|
pod := &corev1.Pod{}
|
|
err := ff.GenerateStruct(pod)
|
|
pod.Kind = "Pod"
|
|
pod.APIVersion = "v1"
|
|
return pod, err
|
|
}
|
|
|
|
func FuzzPodBypass(f *testing.F) {
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
initter.Do(kyvFuzz.InitFuzz)
|
|
|
|
ff := fuzz.NewConsumer(data)
|
|
policyToCheck, err := ff.GetInt()
|
|
if err != nil {
|
|
return
|
|
}
|
|
testPolicy := kyvFuzz.Policies[policyToCheck%11]
|
|
|
|
pod, err := getPod(ff)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
shouldBlock, err := testPolicy.ShouldBlock(pod)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
resource, err := json.MarshalIndent(pod, "", " ")
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
resourceUnstructured, err := kubeutils.BytesToUnstructured(resource)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
pc, err := NewPolicyContext(fuzzJp, *resourceUnstructured, kyverno.Create, nil, fuzzCfg)
|
|
if err != nil {
|
|
return
|
|
}
|
|
er := validateEngine.Validate(
|
|
validateContext,
|
|
pc.WithPolicy(testPolicy.ClusterPolicy),
|
|
)
|
|
failurePolicy := kyverno.Fail
|
|
blocked := blockRequest([]engineapi.EngineResponse{er}, failurePolicy)
|
|
if blocked != shouldBlock {
|
|
panic(fmt.Sprintf("\nDid not block a resource that should be blocked:\n%s\n should have been blocked by \n%+v\n\nshouldBlock was %t\nblocked was %t\n", string(resource), testPolicy.ClusterPolicy, shouldBlock, blocked))
|
|
}
|
|
})
|
|
}
|
|
|
|
func blockRequest(engineResponses []engineapi.EngineResponse, failurePolicy kyverno.FailurePolicyType) bool {
|
|
for _, er := range engineResponses {
|
|
if er.IsFailed() {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func FuzzMutateTest(f *testing.F) {
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
|
|
ff := fuzz.NewConsumer(data)
|
|
//ff.GenerateStruct(policy)
|
|
cpSpec, err := kyvFuzz.CreatePolicySpec(ff)
|
|
if err != nil {
|
|
return
|
|
}
|
|
policy := &kyverno.ClusterPolicy{}
|
|
policy.Spec = cpSpec
|
|
|
|
if len(autogen.ComputeRules(policy)) == 0 {
|
|
return
|
|
}
|
|
|
|
resource, err := kyvFuzz.CreateUnstructuredObject(ff, "")
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// create policy context
|
|
pc, err := NewPolicyContext(
|
|
fuzzJp,
|
|
*resource,
|
|
kyverno.Create,
|
|
nil,
|
|
fuzzCfg,
|
|
)
|
|
if err != nil {
|
|
t.Skip()
|
|
}
|
|
fuzzInterface := kyvFuzz.FuzzInterface{FF: ff}
|
|
e := NewEngine(
|
|
fuzzCfg,
|
|
config.NewDefaultMetricsConfiguration(),
|
|
fuzzJp,
|
|
adapters.Client(fuzzInterface),
|
|
factories.DefaultRegistryClientFactory(adapters.RegistryClient(nil), nil),
|
|
imageverifycache.DisabledImageVerifyCache(),
|
|
factories.DefaultContextLoaderFactory(nil),
|
|
nil,
|
|
"",
|
|
)
|
|
e.Mutate(
|
|
context.Background(),
|
|
pc.WithPolicy(policy),
|
|
)
|
|
})
|
|
}
|