From 005eb715e343a67ffab3f26c79fa1b81bccacea2 Mon Sep 17 00:00:00 2001 From: Jim Bugwadia Date: Tue, 31 Oct 2023 01:41:38 -0700 Subject: [PATCH] add webapp docs and fix related issues (#163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add webapp docs and fix related issues Signed-off-by: Jim Bugwadia * update status Signed-off-by: Jim Bugwadia * update chart meta Signed-off-by: Jim Bugwadia * fixes Signed-off-by: Charles-Edouard Brétéché * fix tests Signed-off-by: Charles-Edouard Brétéché --------- Signed-off-by: Jim Bugwadia Signed-off-by: Charles-Edouard Brétéché Co-authored-by: Charles-Edouard Brétéché --- .github/ISSUE_TEMPLATE/bug.yaml | 2 +- charts/kyverno-json/Chart.yaml | 1 + charts/kyverno-json/README.md | 2 +- pkg/commands/scan/command.go | 4 +- pkg/commands/serve/options.go | 2 +- pkg/json-engine/engine.go | 4 +- pkg/server/linux.go | 2 + pkg/server/scan/handler.go | 6 +- pkg/server/scan/response.go | 63 +++++++++++-- pkg/server/scan/routes.go | 3 + test/commands/scan/dockerfile/out.txt | 2 +- test/commands/scan/payload-yaml/out.txt | 2 +- test/commands/scan/pod-no-latest/out.txt | 2 +- test/commands/scan/tf-plan/out.txt | 2 +- test/commands/scan/tf-s3/out.txt | 2 +- test/commands/scan/wildcard/out.txt | 2 +- .../docs/cli/commands/kyverno-json_scan.md | 4 +- website/docs/cli/index.md | 93 ++++++++++++++++++- website/docs/install.md | 4 +- website/docs/intro.md | 5 +- website/docs/policies/policies.md | 4 +- website/docs/webapp/index.md | 81 +++++++++++++++- 22 files changed, 253 insertions(+), 39 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml index 8a910b6a..8e244b53 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -14,7 +14,7 @@ body: description: >- What version of the Kyverno JSON are you running? options: - - 1.0.0 + - 0.1.0 validations: required: true - type: textarea diff --git a/charts/kyverno-json/Chart.yaml b/charts/kyverno-json/Chart.yaml index afd3f39e..a69e335a 100644 --- a/charts/kyverno-json/Chart.yaml +++ b/charts/kyverno-json/Chart.yaml @@ -13,4 +13,5 @@ sources: maintainers: - name: Nirmata url: https://kyverno.io/ + email: cncf-kyverno-maintainers@lists.cncf.io kubeVersion: ">=1.16.0-0" diff --git a/charts/kyverno-json/README.md b/charts/kyverno-json/README.md index 1ec95255..afdfc3a8 100644 --- a/charts/kyverno-json/README.md +++ b/charts/kyverno-json/README.md @@ -85,7 +85,7 @@ Kubernetes: `>=1.16.0-0` | Name | Email | Url | | ---- | ------ | --- | -| Nirmata | | | +| Nirmata | | | ---------------------------------------------- Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/pkg/commands/scan/command.go b/pkg/commands/scan/command.go index 0e29a2a9..4a20502b 100644 --- a/pkg/commands/scan/command.go +++ b/pkg/commands/scan/command.go @@ -15,9 +15,9 @@ func Command() *cobra.Command { RunE: command.run, } cmd.Flags().StringVar(&command.payload, "payload", "", "Path to payload (json or yaml file)") - cmd.Flags().StringSliceVar(&command.preprocessors, "pre-process", nil, "JmesPath expression used to pre process payload") + cmd.Flags().StringSliceVar(&command.preprocessors, "pre-process", nil, "JMESPath expression used to pre process payload") cmd.Flags().StringSliceVar(&command.policies, "policy", nil, "Path to kyverno-json policies") cmd.Flags().StringSliceVar(&command.selectors, "labels", nil, "Labels selectors for policies") - cmd.Flags().StringVar(&command.identifier, "identifier", "", "JmesPath expression used to identify a resource") + cmd.Flags().StringVar(&command.identifier, "identifier", "", "JMESPath expression used to identify a resource") return cmd } diff --git a/pkg/commands/serve/options.go b/pkg/commands/serve/options.go index 89b99007..a205a4de 100644 --- a/pkg/commands/serve/options.go +++ b/pkg/commands/serve/options.go @@ -39,7 +39,7 @@ type clusterFlags struct { } func (c *options) Run(_ *cobra.Command, _ []string) error { - // initialise gin framework + // initialize gin framework gin.SetMode(c.ginFlags.mode) tonic.SetBindHook(tonic.DefaultBindingHookMaxBodyBytes(int64(c.ginFlags.maxBodySize))) // create router diff --git a/pkg/json-engine/engine.go b/pkg/json-engine/engine.go index 7a5a00f5..586acc4a 100644 --- a/pkg/json-engine/engine.go +++ b/pkg/json-engine/engine.go @@ -63,9 +63,9 @@ func New() engine.Engine[JsonEngineRequest, JsonEngineResponse] { } errs, err := assert.MatchAssert(ctx, nil, r.rule.Assert, r.value, r.bindings) if err != nil { - response.Failure = err - } else if err := multierr.Combine(errs...); err != nil { response.Error = err + } else if err := multierr.Combine(errs...); err != nil { + response.Failure = err } return response }). diff --git a/pkg/server/linux.go b/pkg/server/linux.go index 67d615ce..852bdabe 100644 --- a/pkg/server/linux.go +++ b/pkg/server/linux.go @@ -5,6 +5,7 @@ package server import ( "context" "fmt" + "log" "net/http" "time" ) @@ -21,5 +22,6 @@ func Run(_ context.Context, s Server, host string, port int) Shutdown { panic(err) } }() + log.Default().Printf("listening to requests on %s:%d", host, port) return srv.Shutdown } diff --git a/pkg/server/scan/handler.go b/pkg/server/scan/handler.go index 8ae84525..4118738b 100644 --- a/pkg/server/scan/handler.go +++ b/pkg/server/scan/handler.go @@ -56,6 +56,10 @@ func newHandler(policyProvider PolicyProvider) (gin.HandlerFunc, error) { Resources: resources, Policies: pols, }) - return makeResponse(results...), nil + resp, _ := makeResponse(results...) + // if status != http.StatusOK { + // // TODO: handle HTTP status codes + // } + return resp, nil }, http.StatusOK), nil } diff --git a/pkg/server/scan/response.go b/pkg/server/scan/response.go index d6697ab6..b9dfd36b 100644 --- a/pkg/server/scan/response.go +++ b/pkg/server/scan/response.go @@ -1,7 +1,8 @@ package scan import ( - "github.com/kyverno/kyverno-json/pkg/apis/v1alpha1" + "net/http" + jsonengine "github.com/kyverno/kyverno-json/pkg/json-engine" ) @@ -9,18 +10,60 @@ type Response struct { Results []Result `json:"results"` } +type PolicyResult string + type Result struct { - Policy *v1alpha1.ValidatingPolicy `json:"policy"` - Rule v1alpha1.ValidatingRule `json:"rule"` - Resource interface{} `json:"resource"` - Failure error `json:"failure"` - Error error `json:"error"` + PolicyName string `json:"policy"` + RuleName string `json:"rule"` + Result PolicyResult `json:"status"` + Message string `json:"message"` } -func makeResponse(responses ...jsonengine.JsonEngineResponse) *Response { +// Status specifies state of a policy result +const ( + StatusPass PolicyResult = "pass" + StatusFail PolicyResult = "fail" + StatusWarn PolicyResult = "warn" + StatusError PolicyResult = "error" + StatusSkip PolicyResult = "skip" +) + +func makeResponse(responses ...jsonengine.JsonEngineResponse) (*Response, int) { var response Response - for _, result := range responses { - response.Results = append(response.Results, Result(result)) + failCount := 0 + errorCount := 0 + for _, r := range responses { + status, msg := getStatusAndMessage(r) + if status == StatusError { + errorCount++ + } else if status == StatusFail { + failCount++ + } + + response.Results = append(response.Results, Result{ + PolicyName: r.Policy.Name, + RuleName: r.Rule.Name, + Result: status, + Message: msg, + }) + } + + httpStatus := http.StatusOK + if failCount > 0 { + httpStatus = http.StatusForbidden + } else if errorCount > 0 { + httpStatus = http.StatusNotAcceptable + } + + return &response, httpStatus +} + +func getStatusAndMessage(r jsonengine.JsonEngineResponse) (PolicyResult, string) { + if r.Error != nil { + return StatusError, r.Error.Error() + } + if r.Failure != nil { + return StatusFail, r.Failure.Error() } - return &response + return StatusPass, "" } diff --git a/pkg/server/scan/routes.go b/pkg/server/scan/routes.go index d52dd39f..03c248bb 100644 --- a/pkg/server/scan/routes.go +++ b/pkg/server/scan/routes.go @@ -1,6 +1,8 @@ package scan import ( + "log" + "github.com/gin-gonic/gin" ) @@ -10,5 +12,6 @@ func AddRoutes(group *gin.RouterGroup, policyProvider PolicyProvider) error { return err } group.POST("/scan", handler) + log.Default().Printf("configured route %s/%s", group.BasePath(), "scan") return nil } diff --git a/test/commands/scan/dockerfile/out.txt b/test/commands/scan/dockerfile/out.txt index 4a4a78e7..cb306c06 100644 --- a/test/commands/scan/dockerfile/out.txt +++ b/test/commands/scan/dockerfile/out.txt @@ -2,5 +2,5 @@ Loading policies ... Loading payload ... Pre processing ... Running ( evaluating 1 resource against 1 policy ) ... -- check-dockerfile / deny-external-calls / (unknown) FAILED: HTTP calls are not allowed: all[0].check.~.(Stages[].Commands[].Args[].Value)[0].(contains(@, 'https://') || contains(@, 'http://')): Invalid value: true: Expected value: false; wget is not allowed: all[3].check.~.(Stages[].Commands[].CmdLine[])[0].(contains(@, 'wget')): Invalid value: true: Expected value: false +- check-dockerfile / deny-external-calls / (unknown) ERROR: HTTP calls are not allowed: all[0].check.~.(Stages[].Commands[].Args[].Value)[0].(contains(@, 'https://') || contains(@, 'http://')): Invalid value: true: Expected value: false; wget is not allowed: all[3].check.~.(Stages[].Commands[].CmdLine[])[0].(contains(@, 'wget')): Invalid value: true: Expected value: false Done diff --git a/test/commands/scan/payload-yaml/out.txt b/test/commands/scan/payload-yaml/out.txt index 9a806e35..ce39dff0 100644 --- a/test/commands/scan/payload-yaml/out.txt +++ b/test/commands/scan/payload-yaml/out.txt @@ -2,5 +2,5 @@ Loading policies ... Loading payload ... Pre processing ... Running ( evaluating 1 resource against 1 policy ) ... -- required-s3-tags / require-team-tag / aws_s3_bucket.example FAILED: Bucket `example` (aws_s3_bucket.example) does not have the required tags {"Team":"Kyverno"}: all[0].check.values.tags: Invalid value: map[string]interface {}{"Environment":"Dev", "Name":"My bucket"}: Expected value: map[string]interface {}{"Team":"Kyverno"} +- required-s3-tags / require-team-tag / aws_s3_bucket.example ERROR: Bucket `example` (aws_s3_bucket.example) does not have the required tags {"Team":"Kyverno"}: all[0].check.values.tags: Invalid value: map[string]interface {}{"Environment":"Dev", "Name":"My bucket"}: Expected value: map[string]interface {}{"Team":"Kyverno"} Done diff --git a/test/commands/scan/pod-no-latest/out.txt b/test/commands/scan/pod-no-latest/out.txt index 2e8b82bc..cbd06991 100644 --- a/test/commands/scan/pod-no-latest/out.txt +++ b/test/commands/scan/pod-no-latest/out.txt @@ -2,5 +2,5 @@ Loading policies ... Loading payload ... Pre processing ... Running ( evaluating 1 resource against 1 policy ) ... -- test / pod-no-latest / webserver FAILED: [all[0].check.spec.~foo.containers->foos[0].(at($foos, $foo).image)->foo.(ends_with($foo, $tag)): Invalid value: true: Expected value: false, all[0].check.spec.~foo.containers->foos[1].(at($foos, $foo).image)->foo.(ends_with($foo, $tag)): Invalid value: true: Expected value: false, all[0].check.spec.~foo.containers->foos[2].(at($foos, $foo).image)->foo.(ends_with($foo, $tag)): Invalid value: true: Expected value: false]; [all[1].check.spec.~.containers->foo[0].image.(ends_with(@, ':latest')): Invalid value: true: Expected value: false, all[1].check.spec.~.containers->foo[1].image.(ends_with(@, ':latest')): Invalid value: true: Expected value: false, all[1].check.spec.~.containers->foo[2].image.(ends_with(@, ':latest')): Invalid value: true: Expected value: false]; [all[2].check.~index.(spec.containers[*].image)->images[0].(ends_with(@, ':latest')): Invalid value: true: Expected value: false, all[2].check.~index.(spec.containers[*].image)->images[1].(ends_with(@, ':latest')): Invalid value: true: Expected value: false, all[2].check.~index.(spec.containers[*].image)->images[2].(ends_with(@, ':latest')): Invalid value: true: Expected value: false] +- test / pod-no-latest / webserver ERROR: [all[0].check.spec.~foo.containers->foos[0].(at($foos, $foo).image)->foo.(ends_with($foo, $tag)): Invalid value: true: Expected value: false, all[0].check.spec.~foo.containers->foos[1].(at($foos, $foo).image)->foo.(ends_with($foo, $tag)): Invalid value: true: Expected value: false, all[0].check.spec.~foo.containers->foos[2].(at($foos, $foo).image)->foo.(ends_with($foo, $tag)): Invalid value: true: Expected value: false]; [all[1].check.spec.~.containers->foo[0].image.(ends_with(@, ':latest')): Invalid value: true: Expected value: false, all[1].check.spec.~.containers->foo[1].image.(ends_with(@, ':latest')): Invalid value: true: Expected value: false, all[1].check.spec.~.containers->foo[2].image.(ends_with(@, ':latest')): Invalid value: true: Expected value: false]; [all[2].check.~index.(spec.containers[*].image)->images[0].(ends_with(@, ':latest')): Invalid value: true: Expected value: false, all[2].check.~index.(spec.containers[*].image)->images[1].(ends_with(@, ':latest')): Invalid value: true: Expected value: false, all[2].check.~index.(spec.containers[*].image)->images[2].(ends_with(@, ':latest')): Invalid value: true: Expected value: false] Done diff --git a/test/commands/scan/tf-plan/out.txt b/test/commands/scan/tf-plan/out.txt index 9a806e35..ce39dff0 100644 --- a/test/commands/scan/tf-plan/out.txt +++ b/test/commands/scan/tf-plan/out.txt @@ -2,5 +2,5 @@ Loading policies ... Loading payload ... Pre processing ... Running ( evaluating 1 resource against 1 policy ) ... -- required-s3-tags / require-team-tag / aws_s3_bucket.example FAILED: Bucket `example` (aws_s3_bucket.example) does not have the required tags {"Team":"Kyverno"}: all[0].check.values.tags: Invalid value: map[string]interface {}{"Environment":"Dev", "Name":"My bucket"}: Expected value: map[string]interface {}{"Team":"Kyverno"} +- required-s3-tags / require-team-tag / aws_s3_bucket.example ERROR: Bucket `example` (aws_s3_bucket.example) does not have the required tags {"Team":"Kyverno"}: all[0].check.values.tags: Invalid value: map[string]interface {}{"Environment":"Dev", "Name":"My bucket"}: Expected value: map[string]interface {}{"Team":"Kyverno"} Done diff --git a/test/commands/scan/tf-s3/out.txt b/test/commands/scan/tf-s3/out.txt index de8bef93..76f5a078 100644 --- a/test/commands/scan/tf-s3/out.txt +++ b/test/commands/scan/tf-s3/out.txt @@ -2,5 +2,5 @@ Loading policies ... Loading payload ... Pre processing ... Running ( evaluating 1 resource against 1 policy ) ... -- s3 / check-tags / (unknown) FAILED: all[0].check.planned_values.root_module.~.resources[0].values.(keys(tags_all)).(contains(@, 'Team')): Invalid value: false: Expected value: true +- s3 / check-tags / (unknown) ERROR: all[0].check.planned_values.root_module.~.resources[0].values.(keys(tags_all)).(contains(@, 'Team')): Invalid value: false: Expected value: true Done diff --git a/test/commands/scan/wildcard/out.txt b/test/commands/scan/wildcard/out.txt index 0f416f3c..bc4dae44 100644 --- a/test/commands/scan/wildcard/out.txt +++ b/test/commands/scan/wildcard/out.txt @@ -2,5 +2,5 @@ Loading policies ... Loading payload ... Pre processing ... Running ( evaluating 1 resource against 1 policy ) ... -- required-s3-tags / require-team-tag / bucket1 FAILED: all[0].check.tags.(wildcard('?*', Team)): Invalid value: true: Expected value: false +- required-s3-tags / require-team-tag / bucket1 ERROR: all[0].check.tags.(wildcard('?*', Team)): Invalid value: true: Expected value: false Done diff --git a/website/docs/cli/commands/kyverno-json_scan.md b/website/docs/cli/commands/kyverno-json_scan.md index ed3a701d..e5829940 100644 --- a/website/docs/cli/commands/kyverno-json_scan.md +++ b/website/docs/cli/commands/kyverno-json_scan.md @@ -14,11 +14,11 @@ kyverno-json scan [flags] ``` -h, --help help for scan - --identifier string JmesPath expression used to identify a resource + --identifier string JMESPath expression used to identify a resource --labels strings Labels selectors for policies --payload string Path to payload (json or yaml file) --policy strings Path to kyverno-json policies - --pre-process strings JmesPath expression used to pre process payload + --pre-process strings JMESPath expression used to pre process payload ``` ### SEE ALSO diff --git a/website/docs/cli/index.md b/website/docs/cli/index.md index ce137f78..93862c89 100644 --- a/website/docs/cli/index.md +++ b/website/docs/cli/index.md @@ -1,9 +1,92 @@ -# Usage +# Overview -tbd... +The `kyverno-json` Command Line Interface (CLI) can be used to: -## Pre-processing +* scan JSON or YAML files +* launch a web application with a REST API +* launch a playground -Additionally, you can provide preprocessing queries in [jmespath](https://jmespath.site) format to pre-process the input payload before evaluating *resources* against policies. +Here is an example of scanning an Terraform plan that creates an S3 bucket: -This is necessary if the input payload is not what you want to directly analyse. +```sh +./kyverno-json scan --policy test/commands/scan/tf-s3/policy.yaml --payload test/commands/scan/tf-s3/payload.json +``` + +The output looks like: + +```sh +Loading policies ... +Loading payload ... +Pre processing ... +Running ( evaluating 1 resource against 1 policy ) ... +- s3 / check-tags / (unknown) FAILED: all[0].check.planned_values.root_module.~.resources[0].values.(keys(tags_all)).(contains(@, 'Team')): Invalid value: false: Expected value: true +Done +``` + +## Installation + +See [Install](../install.md) for the available options to install the CLI. + +## Pre-processing payloads + +You can provide preprocessing queries in [jmespath](https://jmespath.site) format to pre-process the input payload before evaluating *resources* against policies. + +This is necessary if the input payload is not what you want to directly analyze. + +For example, here is a partial JSON which was produced by converting a Terraform plan that creates an EC2 instance: + +[kyverno/kyverno-json/main/test/commands/scan/tf-ec2/payload.json](https://github.com/kyverno/kyverno-json/blob/main/test/commands/scan/tf-ec2/payload.json) + +```json +{ + "format_version": "1.2", + "terraform_version": "1.5.7", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "aws_instance.app_server", + "mode": "managed", + "type": "aws_instance", + "name": "app_server", + "provider_name": "registry.terraform.io/hashicorp/aws", + "schema_version": 1, + "values": { + "ami": "ami-830c94e3", + "credit_specification": [], + "get_password_data": false, + "hibernation": null, + "instance_type": "t2.micro", + "launch_template": [], + "source_dest_check": true, + "tags": { + "Name": "ExampleAppServerInstance" + }, + "tags_all": { + "Name": "ExampleAppServerInstance" + }, + "timeouts": null, + "user_data_replace_on_change": false, + "volume_tags": null + }, + + ... + +``` + +To directly scan the `resources` element use `--pre-process planned_values.root_module.resources` as follows: + +```sh +./kyverno-json scan --policy test/commands/scan/tf-ec2/policy.yaml --payload test/commands/scan/tf-ec2/payload.json --pre-process planned_values.root_module.resources +``` + +This command will produce the output: + +```sh +Loading policies ... +Loading payload ... +Pre processing ... +Running ( evaluating 1 resource against 1 policy ) ... +- required-ec2-tags / require-team-tag / (unknown) PASSED +Done +``` diff --git a/website/docs/install.md b/website/docs/install.md index bfcb6f49..eb8190eb 100644 --- a/website/docs/install.md +++ b/website/docs/install.md @@ -2,7 +2,7 @@ You can install the pre-compiled binary (in several ways), or compile from source. -## Install using `go install` +## Using `go install` You can install with `go install` with: @@ -10,7 +10,7 @@ You can install with `go install` with: go install github.com/kyverno/kyverno-json@latest ``` -## Manually +## Download binary Download the pre-compiled binaries from the [releases page](https://github.com/kyverno/kyverno-json/releases) and copy them to the desired location. diff --git a/website/docs/intro.md b/website/docs/intro.md index 0a21d5f3..1ee62fc6 100644 --- a/website/docs/intro.md +++ b/website/docs/intro.md @@ -1,11 +1,11 @@ # Introduction -`kyverno-json` allows any data in JSON (or YAML) format data to be validated with Kyverno policies. For example, you can now use Kyverno policies to validate: +`kyverno-json` extends Kyverno policies to perform simple and efficient validation of data in JSON or YAML format. With `kyverno-json`, you can now use Kyverno policies to validate: - Terraform files - Dockerfiles - Cloud configurations -- Service authorization requests +- Authorization requests Simply convert your runtime or configuration data to JSON, and use Kyverno to audit or enforce policies for security and best practices compliance. @@ -14,4 +14,3 @@ Simply convert your runtime or configuration data to JSON, and use Kyverno to au 1. [A Command Line Interface (CLI)](./cli/index.md) 2. [A web application with a REST API](./webapp/index.md) 3. [A Golang library](./go-library/index.md) - diff --git a/website/docs/policies/policies.md b/website/docs/policies/policies.md index 8db33333..3d18dec1 100644 --- a/website/docs/policies/policies.md +++ b/website/docs/policies/policies.md @@ -2,7 +2,7 @@ Kyverno policies are [Kubernetes resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) and can be easily managed via Kubernetes APIs, GitOps workflows, and other existing tools. -However, policies that apply to JSON payload have a few differences from Kyverno policies that are applied to Kubernetes resources at admission controls. +Policies that apply to JSON payload have a few differences from Kyverno policies that are applied to Kubernetes resources at admission controls. ## Resource Scope @@ -65,7 +65,7 @@ A policy rule can contain `context` entries are made available to the rule via b ```yaml apiVersion: json.kyverno.io/v1alpha1 -kind: Policy +kind: ValidatingPolicy metadata: name: required-s3-tags spec: diff --git a/website/docs/webapp/index.md b/website/docs/webapp/index.md index b878927e..1ce24b16 100644 --- a/website/docs/webapp/index.md +++ b/website/docs/webapp/index.md @@ -1,4 +1,83 @@ # Usage +`kyverno-json` can be deployed as a web application with a REST API. This is useful for deployments when a long running service that processes policy requests is desired. -tbd... \ No newline at end of file +## Managing Policies + +With `kyverno-json` policies are managed as Kubernetes resources. This means that you can use Kubernetes APIs, `kubectl`, GitOps, or any other Kubernetes management tool to manage policies. + +## Usage + +Here is a complete demonstration of how to use `kyverno-json` as an web application: + +**Install CRDs** + +Install the CRD for `kyverno-json`: + +```sh +kubectl apply -f .crds/json.kyverno.io_validatingpolicies.yaml +``` + +**Install policies:** + +Install a sample policy: + +```sh +kubectl apply -f test/commands/scan/dockerfile/policy.yaml +``` + +**Prepare the payload** + +The payload is a JSON object with two fields: + +| Name | Type | Required | +| --------------- | ---------------- | ------------ | +| `payload` | Object | Y | +| `preprocessors` | Array of Strings | N | + + +You can construct a sample payload for the Dockerfile policy using: + +```sh +cat test/commands/scan/dockerfile/payload.json | jq '{"payload": .}' > /tmp/webapp-payload.json +``` + +Run the web application + +```sh +./kyverno-json serve +``` + +This will show the output: + +```sh +2023/10/29 23:46:11 configured route /api/scan +2023/10/29 23:46:11 listening to requests on 0.0.0.0:8080 +``` + +Send the REST API request + +```sh +curl http://localhost:8080/api/scan -X POST -H "Content-Type: application/json" -d @/tmp/webapp-payload.json | jq +``` + +The configured policies will be applied to the payload and the results will be returned back: + +```sh +{ + "results": [ + { + "policy": "check-dockerfile", + "rule": "deny-external-calls", + "status": "fail", + "message": "HTTP calls are not allowed: all[0].check.~.(Stages[].Commands[].Args[].Value)[0].(contains(@, 'https://') || contains(@, 'http://')): Invalid value: true: Expected value: false; wget is not allowed: all[3].check.~.(Stages[].Commands[].CmdLine[])[0].(contains(@, 'wget')): Invalid value: true: Expected value: false" + } + ] +} +``` + +## Helm Chart + +The web application can be installed and managed in a Kubernetes cluster using Helm. + +See details at: https://github.com/kyverno/kyverno-json/tree/main/charts/kyverno-json