1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

feat: add support for background scanning of existing resource in image verification (#10287)

* feat: add support for background scanning of existing resource in image verification

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* fix: change rule response type to image verify

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

* chore: fix nilptr reference

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>

---------

Signed-off-by: Vishal Choudhary <vishal.choudhary@nirmata.com>
This commit is contained in:
Vishal Choudhary 2024-05-24 15:11:04 +05:30 committed by GitHub
parent 1923a6f789
commit 47adea6f1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 419 additions and 5 deletions

View file

@ -66,6 +66,17 @@ func (s *scanner) ScanResource(ctx context.Context, resource unstructured.Unstru
}
spec := pol.GetSpec()
if spec.HasVerifyImages() && len(errors) == 0 {
if response != nil {
// remove responses of verify image rules
ruleResponses := make([]engineapi.RuleResponse, 0, len(response.PolicyResponse.Rules))
for _, v := range response.PolicyResponse.Rules {
if v.RuleType() != engineapi.ImageVerify {
ruleResponses = append(ruleResponses, v)
}
}
response.PolicyResponse.Rules = ruleResponses
}
ivResponse, err := s.validateImages(ctx, resource, nsLabels, pol)
if err != nil {
logger.Error(err, "failed to scan images")
@ -106,6 +117,9 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
WithPolicy(policy).
WithNamespaceLabels(nsLabels)
response := s.engine.Validate(ctx, policyCtx)
if len(response.PolicyResponse.Rules) > 0 {
s.logger.Info("validateResource", "policy", policy, "response", response)
}
return &response, nil
}

View file

@ -53,11 +53,11 @@ func (h validateImageHandler) Process(
key, err := cache.MetaNamespaceKeyFunc(exception)
if err != nil {
logger.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
return resource, handlers.WithError(rule, engineapi.Validation, "failed to compute exception key", err)
return resource, handlers.WithError(rule, engineapi.ImageVerify, "failed to compute exception key", err)
} else {
logger.V(3).Info("policy rule skipped due to policy exception", "exception", key)
return resource, handlers.WithResponses(
engineapi.RuleSkip(rule.Name, engineapi.Validation, "rule skipped due to policy exception "+key).WithException(exception),
engineapi.RuleSkip(rule.Name, engineapi.ImageVerify, "rule skipped due to policy exception "+key).WithException(exception),
)
}
}
@ -90,11 +90,11 @@ func (h validateImageHandler) Process(
logger.V(4).Info("validated image", "rule", rule.Name)
if len(passedImages) > 0 || len(passedImages)+len(skippedImages) == 0 {
if len(skippedImages) > 0 {
return resource, handlers.WithPass(rule, engineapi.Validation, strings.Join(append([]string{"image verified, skipped images:"}, skippedImages...), " "))
return resource, handlers.WithPass(rule, engineapi.ImageVerify, strings.Join(append([]string{"image verified, skipped images:"}, skippedImages...), " "))
}
return resource, handlers.WithPass(rule, engineapi.Validation, "image verified")
return resource, handlers.WithPass(rule, engineapi.ImageVerify, "image verified")
} else {
return resource, handlers.WithSkip(rule, engineapi.Validation, strings.Join(append([]string{"image skipped, skipped images:"}, skippedImages...), " "))
return resource, handlers.WithSkip(rule, engineapi.ImageVerify, strings.Join(append([]string{"image skipped, skipped images:"}, skippedImages...), " "))
}
}

View file

@ -0,0 +1,8 @@
## Description
This test performs a simple verification of an image and creates a policy report for it
## Expected Behavior
Pod creation should pass and report should be generated.

View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: test-verify-images

View file

@ -0,0 +1,45 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: keyed-basic-policy
spec:
background: true
failurePolicy: Fail
webhookTimeoutSeconds: 30
validationFailureAction: Audit
rules:
- match:
any:
- resources:
kinds:
- Pod
name: keyed-basic-rule
verifyImages:
- attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM
5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==
-----END PUBLIC KEY-----
rekor:
ignoreTlog: true
url: https://rekor.sigstore.dev
imageReferences:
- ghcr.io/kyverno/test-verify-image:*
mutateDigest: false
verifyDigest: false
- name: require-ns-purpose-label
match:
any:
- resources:
kinds:
- Pod
validate:
message: "You must have label `purpose` with value `production` set on all new namespaces."
pattern:
metadata:
labels:
foo: bar

View file

@ -0,0 +1,9 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: keyed-basic-policy
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: Pod
metadata:
name: test-secret-pod
namespace: test-verify-images
spec:
containers:
- image: ghcr.io/kyverno/test-verify-image:signed
name: test-secret

View file

@ -0,0 +1,5 @@
apiVersion: v1
kind: Pod
metadata:
name: test-secret-pod
namespace: test-verify-images

View file

@ -0,0 +1,39 @@
apiVersion: v1
items:
- apiVersion: wgpolicyk8s.io/v1alpha2
kind: PolicyReport
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
namespace: test-verify-images
ownerReferences:
- apiVersion: v1
kind: Pod
name: test-secret-pod
results:
- policy: keyed-basic-policy
result: pass
rule: keyed-basic-rule
scored: true
source: kyverno
- message: 'validation error: You must have label `purpose` with value `production`
set on all new namespaces. rule require-ns-purpose-label failed at path /metadata/labels/'
policy: keyed-basic-policy
result: fail
rule: require-ns-purpose-label
scored: true
source: kyverno
scope:
apiVersion: v1
kind: Pod
name: test-secret-pod
namespace: test-verify-images
summary:
error: 0
fail: 1
pass: 1
skip: 0
warn: 0
kind: List
metadata:
resourceVersion: ""

View file

@ -0,0 +1,27 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: verify-image-background-audit
spec:
timeouts:
delete: 2m
steps:
- name: step-01
try:
- apply:
file: chainsaw-step-01-apply-1.yaml
- apply:
file: chainsaw-step-01-apply-2.yaml
- assert:
file: chainsaw-step-01-assert-1.yaml
- name: step-02
try:
- apply:
file: chainsaw-step-02-apply-1.yaml
- assert:
file: chainsaw-step-02-assert-1.yaml
- name: step-03
try:
- assert:
file: chainsaw-step-03-assert-1.yaml

View file

@ -0,0 +1,8 @@
## Description
This test performs a simple verification of an image and creates a policy report for it
## Expected Behavior
Pod creation should pass and report should be generated.

View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: test-verify-images

View file

@ -0,0 +1,33 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: keyed-basic-policy
spec:
background: true
failurePolicy: Fail
webhookTimeoutSeconds: 30
validationFailureAction: Audit
rules:
- match:
any:
- resources:
kinds:
- Pod
name: keyed-basic-rule
verifyImages:
- attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM
5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==
-----END PUBLIC KEY-----
rekor:
ignoreTlog: true
url: https://rekor.sigstore.dev
imageReferences:
- ghcr.io/kyverno/test-verify-image:*
mutateDigest: false
verifyDigest: false

View file

@ -0,0 +1,9 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: keyed-basic-policy
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: Pod
metadata:
name: test-secret-pod
namespace: test-verify-images
spec:
containers:
- image: ghcr.io/kyverno/test-verify-image:signed
name: test-secret

View file

@ -0,0 +1,5 @@
apiVersion: v1
kind: Pod
metadata:
name: test-secret-pod
namespace: test-verify-images

View file

@ -0,0 +1,32 @@
apiVersion: v1
items:
- apiVersion: wgpolicyk8s.io/v1alpha2
kind: PolicyReport
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
namespace: test-verify-images
ownerReferences:
- apiVersion: v1
kind: Pod
name: test-secret-pod
results:
- policy: keyed-basic-policy
result: pass
rule: keyed-basic-rule
scored: true
source: kyverno
scope:
apiVersion: v1
kind: Pod
name: test-secret-pod
namespace: test-verify-images
summary:
error: 0
fail: 0
pass: 1
skip: 0
warn: 0
kind: List
metadata:
resourceVersion: ""

View file

@ -0,0 +1,27 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: verify-image-background-basic
spec:
timeouts:
delete: 2m
steps:
- name: step-01
try:
- apply:
file: chainsaw-step-01-apply-1.yaml
- apply:
file: chainsaw-step-01-apply-2.yaml
- assert:
file: chainsaw-step-01-assert-1.yaml
- name: step-02
try:
- apply:
file: chainsaw-step-02-apply-1.yaml
- assert:
file: chainsaw-step-02-assert-1.yaml
- name: step-03
try:
- assert:
file: chainsaw-step-03-assert-1.yaml

View file

@ -0,0 +1,8 @@
## Description
This test creates background scan reports for image verification.
## Expected Behavior
Pod creation should pass as the image has been signed by the public key specified in the policy.

View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: test-verify-images

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: Pod
metadata:
name: test-secret-pod
namespace: test-verify-images
spec:
containers:
- image: ghcr.io/kyverno/test-verify-image:signed
name: test-secret

View file

@ -0,0 +1,5 @@
apiVersion: v1
kind: Pod
metadata:
name: test-secret-pod
namespace: test-verify-images

View file

@ -0,0 +1,33 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: keyed-basic-policy
spec:
background: true
failurePolicy: Fail
webhookTimeoutSeconds: 30
validationFailureAction: Audit
rules:
- match:
any:
- resources:
kinds:
- Pod
name: keyed-basic-rule
verifyImages:
- attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM
5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA==
-----END PUBLIC KEY-----
rekor:
ignoreTlog: true
url: https://rekor.sigstore.dev
imageReferences:
- ghcr.io/kyverno/test-verify-image:*
mutateDigest: false
verifyDigest: false

View file

@ -0,0 +1,9 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: keyed-basic-policy
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,32 @@
apiVersion: v1
items:
- apiVersion: wgpolicyk8s.io/v1alpha2
kind: PolicyReport
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
namespace: test-verify-images
ownerReferences:
- apiVersion: v1
kind: Pod
name: test-secret-pod
results:
- policy: keyed-basic-policy
result: pass
rule: keyed-basic-rule
scored: true
source: kyverno
scope:
apiVersion: v1
kind: Pod
name: test-secret-pod
namespace: test-verify-images
summary:
error: 0
fail: 0
pass: 1
skip: 0
warn: 0
kind: List
metadata:
resourceVersion: ""

View file

@ -0,0 +1,27 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: verify-image-background-existing
spec:
timeouts:
delete: 2m
steps:
- name: step-01
try:
- apply:
file: chainsaw-step-01-apply-1.yaml
- apply:
file: chainsaw-step-01-apply-2.yaml
- assert:
file: chainsaw-step-01-assert-1.yaml
- name: step-02
try:
- apply:
file: chainsaw-step-02-apply-1.yaml
- assert:
file: chainsaw-step-02-assert-1.yaml
- name: step-03
try:
- assert:
file: chainsaw-step-03-assert-1.yaml