mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-22 07:41:10 +00:00
feat: support json payload via CLI apply command (#12296)
* chore: remove unused code Signed-off-by: ShutingZhao <shuting@nirmata.com> * feat: support json in CLI apply command Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: remove not used validation expressions Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: update codegen docs Signed-off-by: ShutingZhao <shuting@nirmata.com> * chore: add unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> --------- Signed-off-by: ShutingZhao <shuting@nirmata.com>
This commit is contained in:
parent
0bcc850d77
commit
637f756994
9 changed files with 327 additions and 61 deletions
|
@ -11,6 +11,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-git/go-billy/v5/memfs"
|
||||
"github.com/kyverno/kyverno-json/pkg/payload"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
|
||||
policiesv1alpha1 "github.com/kyverno/kyverno/api/policies.kyverno.io/v1alpha1"
|
||||
|
@ -79,6 +80,7 @@ type ApplyCommandConfig struct {
|
|||
inlineExceptions bool
|
||||
GenerateExceptions bool
|
||||
GeneratedExceptionTTL time.Duration
|
||||
JSONPaths []string
|
||||
}
|
||||
|
||||
func Command() *cobra.Command {
|
||||
|
@ -110,6 +112,9 @@ func Command() *cobra.Command {
|
|||
for _, response := range responses {
|
||||
var failedRules []engineapi.RuleResponse
|
||||
resPath := fmt.Sprintf("%s/%s/%s", response.Resource.GetNamespace(), response.Resource.GetKind(), response.Resource.GetName())
|
||||
if resPath == "//" {
|
||||
resPath = "JSON payload"
|
||||
}
|
||||
for _, rule := range response.PolicyResponse.Rules {
|
||||
if rule.Status() == engineapi.RuleStatusFail {
|
||||
failedRules = append(failedRules, rule)
|
||||
|
@ -143,6 +148,8 @@ func Command() *cobra.Command {
|
|||
return exit(out, rc, applyCommandConfig.warnExitCode, applyCommandConfig.warnNoPassed)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringSliceVarP(&applyCommandConfig.JSONPaths, "json", "", []string{}, "Path to JSON payload files")
|
||||
cmd.Flags().StringSliceVarP(&applyCommandConfig.ResourcePaths, "resource", "r", []string{}, "Path to resource files")
|
||||
cmd.Flags().StringSliceVarP(&applyCommandConfig.ResourcePaths, "resources", "", []string{}, "Path to resource files")
|
||||
cmd.Flags().StringSliceVarP(&applyCommandConfig.TargetResourcePaths, "target-resource", "", []string{}, "Path to individual files containing target resources files for policies that have mutate existing")
|
||||
|
@ -209,7 +216,7 @@ func (c *ApplyCommandConfig) applyCommandHelper(out io.Writer) (*processor.Resul
|
|||
}
|
||||
var targetResources []*unstructured.Unstructured
|
||||
if len(c.TargetResourcePaths) > 0 {
|
||||
targetResources, err = c.loadResources(out, c.TargetResourcePaths, policies, vaps, nil)
|
||||
targetResources, _, err = c.loadResources(out, c.TargetResourcePaths, policies, vaps, nil)
|
||||
if err != nil {
|
||||
return nil, nil, skippedInvalidPolicies, nil, err
|
||||
}
|
||||
|
@ -218,7 +225,7 @@ func (c *ApplyCommandConfig) applyCommandHelper(out io.Writer) (*processor.Resul
|
|||
if err != nil {
|
||||
return nil, nil, skippedInvalidPolicies, nil, err
|
||||
}
|
||||
resources, err := c.loadResources(out, c.ResourcePaths, policies, vaps, dClient)
|
||||
resources, jsonPayloads, err := c.loadResources(out, c.ResourcePaths, policies, vaps, dClient)
|
||||
if err != nil {
|
||||
return nil, nil, skippedInvalidPolicies, nil, err
|
||||
}
|
||||
|
@ -247,10 +254,11 @@ func (c *ApplyCommandConfig) applyCommandHelper(out io.Writer) (*processor.Resul
|
|||
policyRulesCount += len(vps)
|
||||
exceptionsCount := len(exceptions)
|
||||
exceptionsCount += len(celexceptions)
|
||||
resourceCount := len(resources) + len(jsonPayloads)
|
||||
if exceptionsCount > 0 {
|
||||
fmt.Fprintf(out, "\nApplying %d policy rule(s) to %d resource(s) with %d exception(s)...\n", policyRulesCount, len(resources), exceptionsCount)
|
||||
fmt.Fprintf(out, "\nApplying %d policy rule(s) to %d resource(s) with %d exception(s)...\n", policyRulesCount, resourceCount, exceptionsCount)
|
||||
} else {
|
||||
fmt.Fprintf(out, "\nApplying %d policy rule(s) to %d resource(s)...\n", policyRulesCount, len(resources))
|
||||
fmt.Fprintf(out, "\nApplying %d policy rule(s) to %d resource(s)...\n", policyRulesCount, resourceCount)
|
||||
}
|
||||
}
|
||||
rc, resources1, responses1, err := c.applyPolicies(
|
||||
|
@ -272,7 +280,7 @@ func (c *ApplyCommandConfig) applyCommandHelper(out io.Writer) (*processor.Resul
|
|||
if err != nil {
|
||||
return rc, resources1, skippedInvalidPolicies, responses1, err
|
||||
}
|
||||
responses3, err := c.applyValidatingPolicies(vps, celexceptions, resources1, variables.Namespace, rc, dClient)
|
||||
responses3, err := c.applyValidatingPolicies(vps, jsonPayloads, celexceptions, resources1, variables.Namespace, rc, dClient)
|
||||
if err != nil {
|
||||
return rc, resources1, skippedInvalidPolicies, responses1, err
|
||||
}
|
||||
|
@ -325,6 +333,7 @@ func (c *ApplyCommandConfig) applyValidatingAdmissionPolicies(
|
|||
|
||||
func (c *ApplyCommandConfig) applyValidatingPolicies(
|
||||
vps []policiesv1alpha1.ValidatingPolicy,
|
||||
jsonPayloads []*unstructured.Unstructured,
|
||||
exceptions []*policiesv1alpha1.CELPolicyException,
|
||||
resources []*unstructured.Unstructured,
|
||||
namespaceProvider func(string) *corev1.Namespace,
|
||||
|
@ -355,6 +364,7 @@ func (c *ApplyCommandConfig) applyValidatingPolicies(
|
|||
}
|
||||
restMapper := restmapper.NewDiscoveryRESTMapper(apiGroupResources)
|
||||
responses := make([]engineapi.EngineResponse, 0)
|
||||
responsesTemp := make([]engine.EngineResponse, 0)
|
||||
for _, resource := range resources {
|
||||
// get gvk from resource
|
||||
gvk := resource.GroupVersionKind()
|
||||
|
@ -384,7 +394,7 @@ func (c *ApplyCommandConfig) applyValidatingPolicies(
|
|||
false,
|
||||
nil,
|
||||
)
|
||||
response, err := eng.Handle(ctx, request)
|
||||
reps, err := eng.Handle(ctx, request)
|
||||
if err != nil {
|
||||
if c.ContinueOnFail {
|
||||
fmt.Printf("failed to apply validating policies on resource %s (%v)\n", resource.GetName(), err)
|
||||
|
@ -392,7 +402,25 @@ func (c *ApplyCommandConfig) applyValidatingPolicies(
|
|||
}
|
||||
return responses, fmt.Errorf("failed to apply validating policies on resource %s (%w)", resource.GetName(), err)
|
||||
}
|
||||
// transform response into legacy engine responses
|
||||
responsesTemp = append(responsesTemp, reps)
|
||||
}
|
||||
|
||||
for _, json := range jsonPayloads {
|
||||
eng = engine.NewEngine(provider, nil, nil)
|
||||
request := engine.RequestFromJSON(contextProvider, json)
|
||||
reps, err := eng.Handle(ctx, request)
|
||||
if err != nil {
|
||||
if c.ContinueOnFail {
|
||||
fmt.Printf("failed to apply validating policies on JSON payloads (%v)\n", err)
|
||||
continue
|
||||
}
|
||||
return responses, fmt.Errorf("failed to apply validating policies on JSON payloads (%w)", err)
|
||||
}
|
||||
responsesTemp = append(responsesTemp, reps)
|
||||
}
|
||||
|
||||
// transform response into legacy engine responses
|
||||
for _, response := range responsesTemp {
|
||||
for _, r := range response.Policies {
|
||||
engineResponse := engineapi.EngineResponse{
|
||||
Resource: *response.Resource,
|
||||
|
@ -482,12 +510,24 @@ func (c *ApplyCommandConfig) applyPolicies(
|
|||
return &rc, resources, responses, nil
|
||||
}
|
||||
|
||||
func (c *ApplyCommandConfig) loadResources(out io.Writer, paths []string, policies []kyvernov1.PolicyInterface, vap []admissionregistrationv1.ValidatingAdmissionPolicy, dClient dclient.Interface) ([]*unstructured.Unstructured, error) {
|
||||
func (c *ApplyCommandConfig) loadResources(out io.Writer, paths []string, policies []kyvernov1.PolicyInterface, vap []admissionregistrationv1.ValidatingAdmissionPolicy, dClient dclient.Interface) ([]*unstructured.Unstructured, []*unstructured.Unstructured, error) {
|
||||
resources, err := common.GetResourceAccordingToResourcePath(out, nil, paths, c.Cluster, policies, vap, dClient, c.Namespace, c.PolicyReport, "")
|
||||
if err != nil {
|
||||
return resources, fmt.Errorf("failed to load resources (%w)", err)
|
||||
return resources, nil, fmt.Errorf("failed to load resources (%w)", err)
|
||||
}
|
||||
return resources, nil
|
||||
|
||||
var jsonPayloads []*unstructured.Unstructured
|
||||
if len(c.JSONPaths) > 0 {
|
||||
for _, path := range c.JSONPaths {
|
||||
payload, err := payload.Load(path)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to load JSON payload (%w)", err)
|
||||
}
|
||||
|
||||
jsonPayloads = append(jsonPayloads, &unstructured.Unstructured{Object: payload.(map[string]interface{})})
|
||||
}
|
||||
}
|
||||
return resources, jsonPayloads, nil
|
||||
}
|
||||
|
||||
func (c *ApplyCommandConfig) loadPolicies() (
|
||||
|
@ -632,7 +672,7 @@ func (c *ApplyCommandConfig) checkArguments() error {
|
|||
if (len(c.PolicyPaths) > 0 && c.PolicyPaths[0] == "-") && len(c.ResourcePaths) > 0 && c.ResourcePaths[0] == "-" {
|
||||
return fmt.Errorf("a stdin pipe can be used for either policies or resources, not both")
|
||||
}
|
||||
if len(c.ResourcePaths) == 0 && !c.Cluster {
|
||||
if len(c.ResourcePaths) == 0 && !c.Cluster && len(c.JSONPaths) == 0 {
|
||||
return fmt.Errorf("resource file(s) or cluster required")
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -145,24 +145,6 @@ func Test_Apply(t *testing.T) {
|
|||
},
|
||||
}},
|
||||
},
|
||||
// {
|
||||
// // TODO
|
||||
// config: ApplyCommandConfig{
|
||||
// PolicyPaths: []string{"https://github.com/kyverno/policies/openshift/team-validate-ns-name/"},
|
||||
// ResourcePaths: []string{"../../../../../test/openshift/team-validate-ns-name.yaml"},
|
||||
// GitBranch: "main",
|
||||
// PolicyReport: true,
|
||||
// },
|
||||
// expectedPolicyReports: []policyreportv1alpha2.PolicyReport{{
|
||||
// Summary: policyreportv1alpha2.PolicyReportSummary{
|
||||
// Pass: 2,
|
||||
// Fail: 0,
|
||||
// Skip: 0,
|
||||
// Error: 0,
|
||||
// Warn: 0,
|
||||
// },
|
||||
// }},
|
||||
// },
|
||||
{
|
||||
config: ApplyCommandConfig{
|
||||
PolicyPaths: []string{"../../../../../test/cli/apply/policies-set"},
|
||||
|
@ -537,6 +519,22 @@ func Test_Apply_ValidatingPolicies(t *testing.T) {
|
|||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
config: ApplyCommandConfig{
|
||||
PolicyPaths: []string{"../../../../../test/cli/test-validating-policy/json-check-dockerfile/policy.yaml"},
|
||||
JSONPaths: []string{"../../../../../test/cli/test-validating-policy/json-check-dockerfile/payload.json"},
|
||||
PolicyReport: true,
|
||||
},
|
||||
expectedPolicyReports: []policyreportv1alpha2.PolicyReport{{
|
||||
Summary: policyreportv1alpha2.PolicyReportSummary{
|
||||
Pass: 1,
|
||||
Fail: 1,
|
||||
Skip: 0,
|
||||
Error: 0,
|
||||
Warn: 0,
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
config: ApplyCommandConfig{
|
||||
PolicyPaths: []string{"../../../../../test/cli/test-cel-exceptions/check-deployment-labels/policy.yaml"},
|
||||
|
@ -610,7 +608,7 @@ func Test_Apply_ValidatingPolicies(t *testing.T) {
|
|||
_ = input.Close()
|
||||
}()
|
||||
}
|
||||
desc := fmt.Sprintf("Policies: [%s], / Resources: [%s]", strings.Join(tc.config.PolicyPaths, ","), strings.Join(tc.config.ResourcePaths, ","))
|
||||
desc := fmt.Sprintf("Policies: [%s], / Resources: [%s], JSON payload: [%s]", strings.Join(tc.config.PolicyPaths, ","), strings.Join(tc.config.ResourcePaths, ","), strings.Join(tc.config.JSONPaths, ","))
|
||||
|
||||
_, _, _, responses, err := tc.config.applyCommandHelper(os.Stdout)
|
||||
assert.NoError(t, err, desc)
|
||||
|
|
|
@ -37,7 +37,7 @@ func GetResourceAccordingToResourcePath(
|
|||
policyResourcePath string,
|
||||
) (resources []*unstructured.Unstructured, err error) {
|
||||
if fs != nil {
|
||||
resources, err = GetResourcesWithTest(out, fs, policies, resourcePaths, policyResourcePath)
|
||||
resources, err = GetResourcesWithTest(out, fs, resourcePaths, policyResourcePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract the resources (%w)", err)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource"
|
||||
"github.com/kyverno/kyverno/pkg/admissionpolicy"
|
||||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||
|
@ -126,16 +125,8 @@ func whenClusterIsFalse(out io.Writer, resourcePaths []string, policyReport bool
|
|||
}
|
||||
|
||||
// GetResourcesWithTest with gets matched resources by the given policies
|
||||
func GetResourcesWithTest(out io.Writer, fs billy.Filesystem, policies []kyvernov1.PolicyInterface, resourcePaths []string, policyResourcePath string) ([]*unstructured.Unstructured, error) {
|
||||
func GetResourcesWithTest(out io.Writer, fs billy.Filesystem, resourcePaths []string, policyResourcePath string) ([]*unstructured.Unstructured, error) {
|
||||
resources := make([]*unstructured.Unstructured, 0)
|
||||
resourceTypesMap := make(map[string]bool)
|
||||
for _, policy := range policies {
|
||||
for _, rule := range autogen.Default.ComputeRules(policy, "") {
|
||||
for _, kind := range rule.MatchResources.Kinds {
|
||||
resourceTypesMap[kind] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(resourcePaths) > 0 {
|
||||
for _, resourcePath := range resourcePaths {
|
||||
var resourceBytes []byte
|
||||
|
|
|
@ -49,6 +49,7 @@ kyverno apply [flags]
|
|||
--generated-exception-ttl duration Default TTL for generated exceptions (default 720h0m0s)
|
||||
-b, --git-branch string test git repository branch
|
||||
-h, --help help for apply
|
||||
--json strings Path to JSON payload files
|
||||
--kubeconfig string path to kubeconfig file with authorization and master location information
|
||||
-n, --namespace string Optional Policy parameter passed with cluster flag
|
||||
-o, --output string Prints the mutated/generated resources in provided file/directory
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
vpolautogen "github.com/kyverno/kyverno/pkg/cel/autogen"
|
||||
contextlib "github.com/kyverno/kyverno/pkg/cel/libs/context"
|
||||
"github.com/kyverno/kyverno/pkg/cel/matching"
|
||||
celpolicy "github.com/kyverno/kyverno/pkg/cel/policy"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/handlers"
|
||||
admissionutils "github.com/kyverno/kyverno/pkg/utils/admission"
|
||||
|
@ -25,8 +26,9 @@ import (
|
|||
)
|
||||
|
||||
type EngineRequest struct {
|
||||
request admissionv1.AdmissionRequest
|
||||
context contextlib.ContextInterface
|
||||
jsonPayload *unstructured.Unstructured
|
||||
request admissionv1.AdmissionRequest
|
||||
context contextlib.ContextInterface
|
||||
}
|
||||
|
||||
func RequestFromAdmission(context contextlib.ContextInterface, request admissionv1.AdmissionRequest) EngineRequest {
|
||||
|
@ -36,6 +38,13 @@ func RequestFromAdmission(context contextlib.ContextInterface, request admission
|
|||
}
|
||||
}
|
||||
|
||||
func RequestFromJSON(context contextlib.ContextInterface, jsonPayload *unstructured.Unstructured) EngineRequest {
|
||||
return EngineRequest{
|
||||
jsonPayload: jsonPayload,
|
||||
context: context,
|
||||
}
|
||||
}
|
||||
|
||||
func Request(
|
||||
context contextlib.ContextInterface,
|
||||
gvk schema.GroupVersionKind,
|
||||
|
@ -111,6 +120,15 @@ func (e *engine) Handle(ctx context.Context, request EngineRequest) (EngineRespo
|
|||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
if request.jsonPayload != nil {
|
||||
response.Resource = request.jsonPayload
|
||||
for _, policy := range policies {
|
||||
response.Policies = append(response.Policies, e.handlePolicy(ctx, policy, request.jsonPayload.Object, nil, nil, nil, request.context))
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// load objects
|
||||
object, oldObject, err := admissionutils.ExtractResources(nil, request.request)
|
||||
if err != nil {
|
||||
|
@ -147,7 +165,7 @@ func (e *engine) Handle(ctx context.Context, request EngineRequest) (EngineRespo
|
|||
}
|
||||
// evaluate policies
|
||||
for _, policy := range policies {
|
||||
response.Policies = append(response.Policies, e.handlePolicy(ctx, policy, attr, &request.request, namespace, request.context))
|
||||
response.Policies = append(response.Policies, e.handlePolicy(ctx, policy, nil, attr, &request.request, namespace, request.context))
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
@ -163,12 +181,14 @@ func (e *engine) matchPolicy(policy CompiledPolicy, attr admission.Attributes, n
|
|||
}
|
||||
|
||||
// match against main policy constraints
|
||||
matches, err := match(policy.Policy.Spec.MatchConstraints)
|
||||
if err != nil {
|
||||
return false, -1, err
|
||||
}
|
||||
if matches {
|
||||
return true, -1, nil
|
||||
if policy.Policy.GetSpec().MatchConstraints != nil {
|
||||
matches, err := match(policy.Policy.Spec.MatchConstraints)
|
||||
if err != nil {
|
||||
return false, -1, err
|
||||
}
|
||||
if matches {
|
||||
return true, -1, nil
|
||||
}
|
||||
}
|
||||
|
||||
// match against autogen rules
|
||||
|
@ -185,7 +205,7 @@ func (e *engine) matchPolicy(policy CompiledPolicy, attr admission.Attributes, n
|
|||
return false, -1, nil
|
||||
}
|
||||
|
||||
func (e *engine) handlePolicy(ctx context.Context, policy CompiledPolicy, attr admission.Attributes, request *admissionv1.AdmissionRequest, namespace runtime.Object, context contextlib.ContextInterface) PolicyResponse {
|
||||
func (e *engine) handlePolicy(ctx context.Context, policy CompiledPolicy, jsonPayload interface{}, attr admission.Attributes, request *admissionv1.AdmissionRequest, namespace runtime.Object, context contextlib.ContextInterface) PolicyResponse {
|
||||
response := PolicyResponse{
|
||||
Actions: policy.Actions,
|
||||
Policy: policy.Policy,
|
||||
|
@ -201,7 +221,15 @@ func (e *engine) handlePolicy(ctx context.Context, policy CompiledPolicy, attr a
|
|||
}
|
||||
autogenIndex = index
|
||||
}
|
||||
result, err := policy.CompiledPolicy.Evaluate(ctx, nil, attr, request, namespace, context, autogenIndex)
|
||||
|
||||
var result *celpolicy.EvaluationResult
|
||||
var err error
|
||||
if jsonPayload != nil {
|
||||
result, err = policy.CompiledPolicy.Evaluate(ctx, jsonPayload, nil, nil, nil, context, -1)
|
||||
} else {
|
||||
result, err = policy.CompiledPolicy.Evaluate(ctx, nil, attr, request, namespace, context, autogenIndex)
|
||||
}
|
||||
|
||||
// TODO: error is about match conditions here ?
|
||||
if err != nil {
|
||||
response.Rules = handlers.WithResponses(engineapi.RuleError("evaluation", engineapi.Validation, "failed to load context", err, nil))
|
||||
|
|
|
@ -25,14 +25,6 @@ func Test_evaluateJson(t *testing.T) {
|
|||
{
|
||||
"message": "HTTP calls are not allowed",
|
||||
"expression": "!object.Stages.exists(s, \n s.Commands.exists(c, \n c.Args.exists(a, \n a.Value.contains('http://') || a.Value.contains('https://')\n )\n )\n)"
|
||||
},
|
||||
{
|
||||
"message": "curl is not allowed",
|
||||
"expression": "!object.Stages.exists(s, \n s.Commands.exists(c, \n c.CmdLine.contains('curl')\n )\n)"
|
||||
},
|
||||
{
|
||||
"message": "wget is not allowed",
|
||||
"expression": "!object.Stages.exists(s, \n s.Commands.exists(c, \n c.CmdLine.contains('wget')\n )\n)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -242,5 +234,5 @@ func Test_evaluateJson(t *testing.T) {
|
|||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
t.Log(result)
|
||||
assert.Assert(t, result.Result == false)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
{
|
||||
"MetaArgs": [
|
||||
{
|
||||
"Key": "BUILD_PLATFORM",
|
||||
"DefaultValue": "\"linux/amd64\"",
|
||||
"ProvidedValue": null,
|
||||
"Value": "\"linux/amd64\""
|
||||
},
|
||||
{
|
||||
"Key": "BUILDER_IMAGE",
|
||||
"DefaultValue": "\"golang:1.20.6-alpine3.18\"",
|
||||
"ProvidedValue": null,
|
||||
"Value": "\"golang:1.20.6-alpine3.18\""
|
||||
}
|
||||
],
|
||||
"Stages": [
|
||||
{
|
||||
"Name": "builder",
|
||||
"BaseName": "\"golang:1.20.6-alpine3.18\"",
|
||||
"Platform": "$BUILD_PLATFORM",
|
||||
"Comment": "",
|
||||
"SourceCode": "FROM --platform=$BUILD_PLATFORM $BUILDER_IMAGE as builder",
|
||||
"Location": [
|
||||
{
|
||||
"Start": {
|
||||
"Line": 4,
|
||||
"Character": 0
|
||||
},
|
||||
"End": {
|
||||
"Line": 4,
|
||||
"Character": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"As": "builder",
|
||||
"From": {
|
||||
"Image": "\"golang:1.20.6-alpine3.18\""
|
||||
},
|
||||
"Commands": [
|
||||
{
|
||||
"Name": "WORKDIR",
|
||||
"Path": "/"
|
||||
},
|
||||
{
|
||||
"Chmod": "",
|
||||
"Chown": "",
|
||||
"DestPath": "./",
|
||||
"From": "",
|
||||
"Link": false,
|
||||
"Name": "COPY",
|
||||
"SourceContents": null,
|
||||
"SourcePaths": [
|
||||
"."
|
||||
]
|
||||
},
|
||||
{
|
||||
"Args": [
|
||||
{
|
||||
"Comment": "",
|
||||
"Key": "SIGNER_BINARY_LINK",
|
||||
"Value": "\"https://d2hvyiie56hcat.cloudfront.net/linux/amd64/plugin/latest/notation-aws-signer-plugin.zip\""
|
||||
}
|
||||
],
|
||||
"Name": "ARG"
|
||||
},
|
||||
{
|
||||
"Args": [
|
||||
{
|
||||
"Comment": "",
|
||||
"Key": "SIGNER_BINARY_FILE",
|
||||
"Value": "\"notation-aws-signer-plugin.zip\""
|
||||
}
|
||||
],
|
||||
"Name": "ARG"
|
||||
},
|
||||
{
|
||||
"CmdLine": [
|
||||
"wget -O ${SIGNER_BINARY_FILE} ${SIGNER_BINARY_LINK}"
|
||||
],
|
||||
"Files": null,
|
||||
"FlagsUsed": [],
|
||||
"Name": "RUN",
|
||||
"PrependShell": true
|
||||
},
|
||||
{
|
||||
"CmdLine": [
|
||||
"apk update && apk add unzip && unzip -o ${SIGNER_BINARY_FILE}"
|
||||
],
|
||||
"Files": null,
|
||||
"FlagsUsed": [],
|
||||
"Name": "RUN",
|
||||
"PrependShell": true
|
||||
},
|
||||
{
|
||||
"CmdLine": [
|
||||
"GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags=\"-w -s\" -o kyverno-notation-aws ."
|
||||
],
|
||||
"Files": null,
|
||||
"FlagsUsed": [],
|
||||
"Name": "RUN",
|
||||
"PrependShell": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "",
|
||||
"BaseName": "gcr.io/distroless/static:nonroot",
|
||||
"Platform": "",
|
||||
"Comment": "",
|
||||
"SourceCode": "FROM gcr.io/distroless/static:nonroot",
|
||||
"Location": [
|
||||
{
|
||||
"Start": {
|
||||
"Line": 20,
|
||||
"Character": 0
|
||||
},
|
||||
"End": {
|
||||
"Line": 20,
|
||||
"Character": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"From": {
|
||||
"Image": "gcr.io/distroless/static:nonroot"
|
||||
},
|
||||
"Commands": [
|
||||
{
|
||||
"Name": "WORKDIR",
|
||||
"Path": "/"
|
||||
},
|
||||
{
|
||||
"Env": [
|
||||
{
|
||||
"Key": "PLUGINS_DIR",
|
||||
"Value": "/plugins"
|
||||
}
|
||||
],
|
||||
"Name": "ENV"
|
||||
},
|
||||
{
|
||||
"Chmod": "",
|
||||
"Chown": "",
|
||||
"DestPath": "plugins/com.amazonaws.signer.notation.plugin/notation-com.amazonaws.signer.notation.plugin",
|
||||
"From": "builder",
|
||||
"Link": false,
|
||||
"Name": "COPY",
|
||||
"SourceContents": null,
|
||||
"SourcePaths": [
|
||||
"notation-com.amazonaws.signer.notation.plugin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Chmod": "",
|
||||
"Chown": "",
|
||||
"DestPath": "kyverno-notation-aws",
|
||||
"From": "builder",
|
||||
"Link": false,
|
||||
"Name": "COPY",
|
||||
"SourceContents": null,
|
||||
"SourcePaths": [
|
||||
"kyverno-notation-aws"
|
||||
]
|
||||
},
|
||||
{
|
||||
"CmdLine": [
|
||||
"/kyverno-notation-aws"
|
||||
],
|
||||
"Files": null,
|
||||
"Name": "ENTRYPOINT",
|
||||
"PrependShell": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
apiVersion: policies.kyverno.io/v1alpha1
|
||||
kind: ValidatingPolicy
|
||||
metadata:
|
||||
name: check-dockerfile-disallow-curl
|
||||
spec:
|
||||
evaluation:
|
||||
mode: JSON
|
||||
validations:
|
||||
- message: "curl is not allowed"
|
||||
expression: >-
|
||||
!object.Stages.exists(s,
|
||||
s.Commands.exists(c,
|
||||
has(c.CmdLine) && c.CmdLine.exists(cmd, string(cmd).contains('curl'))
|
||||
)
|
||||
)
|
||||
---
|
||||
apiVersion: policies.kyverno.io/v1alpha1
|
||||
kind: ValidatingPolicy
|
||||
metadata:
|
||||
name: check-dockerfile-disallow-wget
|
||||
spec:
|
||||
evaluation:
|
||||
mode: JSON
|
||||
validations:
|
||||
- message: "wget is not allowed"
|
||||
expression: >-
|
||||
!object.Stages.exists(s,
|
||||
s.Commands.exists(c,
|
||||
has(c.CmdLine) && c.CmdLine.exists(cmd, string(cmd).contains('wget'))
|
||||
)
|
||||
)
|
||||
- message: "HTTP calls are not allowed"
|
||||
expression: >-
|
||||
!object.Stages.exists(s,
|
||||
s.Commands.exists(c,
|
||||
c.Args.exists(a,
|
||||
a.Value.contains('http://') || a.Value.contains('https://')
|
||||
)
|
||||
)
|
||||
)
|
Loading…
Add table
Reference in a new issue