mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-15 12:17:56 +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:
parent
1923a6f789
commit
47adea6f1c
26 changed files with 419 additions and 5 deletions
|
@ -66,6 +66,17 @@ func (s *scanner) ScanResource(ctx context.Context, resource unstructured.Unstru
|
||||||
}
|
}
|
||||||
spec := pol.GetSpec()
|
spec := pol.GetSpec()
|
||||||
if spec.HasVerifyImages() && len(errors) == 0 {
|
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)
|
ivResponse, err := s.validateImages(ctx, resource, nsLabels, pol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to scan images")
|
logger.Error(err, "failed to scan images")
|
||||||
|
@ -106,6 +117,9 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
|
||||||
WithPolicy(policy).
|
WithPolicy(policy).
|
||||||
WithNamespaceLabels(nsLabels)
|
WithNamespaceLabels(nsLabels)
|
||||||
response := s.engine.Validate(ctx, policyCtx)
|
response := s.engine.Validate(ctx, policyCtx)
|
||||||
|
if len(response.PolicyResponse.Rules) > 0 {
|
||||||
|
s.logger.Info("validateResource", "policy", policy, "response", response)
|
||||||
|
}
|
||||||
return &response, nil
|
return &response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,11 +53,11 @@ func (h validateImageHandler) Process(
|
||||||
key, err := cache.MetaNamespaceKeyFunc(exception)
|
key, err := cache.MetaNamespaceKeyFunc(exception)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
|
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 {
|
} else {
|
||||||
logger.V(3).Info("policy rule skipped due to policy exception", "exception", key)
|
logger.V(3).Info("policy rule skipped due to policy exception", "exception", key)
|
||||||
return resource, handlers.WithResponses(
|
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)
|
logger.V(4).Info("validated image", "rule", rule.Name)
|
||||||
if len(passedImages) > 0 || len(passedImages)+len(skippedImages) == 0 {
|
if len(passedImages) > 0 || len(passedImages)+len(skippedImages) == 0 {
|
||||||
if 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 {
|
} 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...), " "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test-verify-images
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: keyed-basic-policy
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: test-secret-pod
|
||||||
|
namespace: test-verify-images
|
|
@ -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: ""
|
|
@ -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
|
|
@ -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.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test-verify-images
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: keyed-basic-policy
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: test-secret-pod
|
||||||
|
namespace: test-verify-images
|
|
@ -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: ""
|
|
@ -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
|
|
@ -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.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: test-verify-images
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: test-secret-pod
|
||||||
|
namespace: test-verify-images
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
apiVersion: kyverno.io/v1
|
||||||
|
kind: ClusterPolicy
|
||||||
|
metadata:
|
||||||
|
name: keyed-basic-policy
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- reason: Succeeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
|
@ -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: ""
|
|
@ -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
|
Loading…
Add table
Reference in a new issue