From 6e48fdf4cece25a92f9e90d49e2d16ab39cf9612 Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Wed, 4 May 2022 18:38:56 +0100 Subject: [PATCH] Fix issue with image registry when decoding OCI descriptors with out of spec keys (#3799) --- pkg/engine/jsonContext.go | 16 ++++++++-- test/cli/registry/image-example.yaml | 44 ++++++++++++++++++++++++++-- test/cli/registry/kyverno-test.yaml | 6 +++- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/pkg/engine/jsonContext.go b/pkg/engine/jsonContext.go index 168102bac0..da0a5e939d 100644 --- a/pkg/engine/jsonContext.go +++ b/pkg/engine/jsonContext.go @@ -187,14 +187,24 @@ func fetchImageDataMap(ref string) (interface{}, error) { if err != nil { return nil, fmt.Errorf("failed to resolve image reference: %s, error: %v", ref, err) } - manifest, err := image.Manifest() + // We need to use the raw config and manifest to avoid dropping unknown keys + // which are not defined in GGCR structs. + rawManifest, err := image.RawManifest() if err != nil { return nil, fmt.Errorf("failed to fetch manifest for image reference: %s, error: %v", ref, err) } - config, err := image.ConfigFile() + var manifest interface{} + if err := json.Unmarshal(rawManifest, &manifest); err != nil { + return nil, fmt.Errorf("failed to decode manifest for image reference: %s, error: %v", ref, err) + } + rawConfig, err := image.RawConfigFile() if err != nil { return nil, fmt.Errorf("failed to fetch config for image reference: %s, error: %v", ref, err) } + var configData interface{} + if err := json.Unmarshal(rawConfig, &configData); err != nil { + return nil, fmt.Errorf("failed to decode config for image reference: %s, error: %v", ref, err) + } data := map[string]interface{}{ "image": ref, "resolvedImage": fmt.Sprintf("%s@%s", parsedRef.Context().Name(), desc.Digest.String()), @@ -202,7 +212,7 @@ func fetchImageDataMap(ref string) (interface{}, error) { "repository": parsedRef.Context().RepositoryStr(), "identifier": parsedRef.Identifier(), "manifest": manifest, - "configData": config, + "configData": configData, } // we need to do the conversion from struct types to an interface type so that jmespath // evaluation works correctly. go-jmespath cannot handle function calls like max/sum diff --git a/test/cli/registry/image-example.yaml b/test/cli/registry/image-example.yaml index e24d127915..4d13aa6b2c 100644 --- a/test/cli/registry/image-example.yaml +++ b/test/cli/registry/image-example.yaml @@ -1,3 +1,4 @@ +--- apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: @@ -15,12 +16,12 @@ spec: operator: NotEquals value: DELETE validate: - message: "images with root user are not allowed" + message: "images with root user are not allowed" foreach: - list: "request.object.spec.containers" - context: + context: - name: imageData - imageRegistry: + imageRegistry: reference: "{{ element.image }}" deny: conditions: @@ -31,3 +32,40 @@ spec: - key: "{{ imageData.registry }}" operator: NotEquals value: "ghcr.io" +--- +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: check-image-base +spec: + validationFailureAction: enforce + rules: + - name: check-image-base-rule + match: + any: + - resources: + kinds: + - Pod + preconditions: + all: + - key: "{{request.operation}}" + operator: NotEquals + value: DELETE + validate: + message: "Images must specify a source/base image from which they are built to be valid." + foreach: + - list: "request.object.spec.containers" + context: + - name: imageData + imageRegistry: + reference: "{{ element.image }}" + - name: mobysource + variable: + jmesPath: imageData.configData."moby.buildkit.buildinfo.v1" | base64_decode(@).parse_json(@) | sources[].ref | length(@) + default: 0 + deny: + conditions: + all: + - key: "{{ mobysource }}" + operator: Equals + value: 0 \ No newline at end of file diff --git a/test/cli/registry/kyverno-test.yaml b/test/cli/registry/kyverno-test.yaml index 085d0867ed..c93686bd75 100644 --- a/test/cli/registry/kyverno-test.yaml +++ b/test/cli/registry/kyverno-test.yaml @@ -14,4 +14,8 @@ results: resource: test-pod-with-trusted-registry kind: Pod status: pass - + - policy: check-image-base + rule: check-image-base-rule + resource: test-pod-with-trusted-registry + kind: Pod + status: pass