1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 02:18:15 +00:00

feat: generate VAPs from exceptions (#10771)

Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
Mariam Fahmy 2024-08-13 14:55:22 +03:00 committed by GitHub
parent 3a69702b49
commit 25b7142ee0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 1044 additions and 31 deletions

View file

@ -266,18 +266,19 @@ func (c *controller) getValidatingAdmissionPolicyBinding(name string) (*admissio
return vapbinding, nil
}
// hasExceptions checks if there is an exception that match both the policy and the rule.
func (c *controller) hasExceptions(policyName, rule string) (bool, error) {
// getExceptions get exceptions that match both the policy and the rule if exists.
func (c *controller) getExceptions(policyName, rule string) ([]kyvernov2.PolicyException, error) {
var exceptions []kyvernov2.PolicyException
polexs, err := c.polexLister.List(labels.Everything())
if err != nil {
return false, err
return nil, err
}
for _, polex := range polexs {
if polex.Contains(policyName, rule) {
return true, nil
exceptions = append(exceptions, *polex)
}
}
return false, nil
return exceptions, nil
}
func constructVapBindingName(vapName string) string {
@ -319,11 +320,12 @@ func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, nam
observedVAP, vapErr := c.getValidatingAdmissionPolicy(vapName)
observedVAPbinding, vapBindingErr := c.getValidatingAdmissionPolicyBinding(vapBindingName)
hasExceptions, err := c.hasExceptions(name, spec.Rules[0].Name)
exceptions, err := c.getExceptions(name, spec.Rules[0].Name)
if err != nil {
return err
}
if ok, msg := validatingadmissionpolicy.CanGenerateVAP(spec); !ok || hasExceptions {
if ok, msg := validatingadmissionpolicy.CanGenerateVAP(spec, exceptions); !ok {
// delete the ValidatingAdmissionPolicy if exist
if vapErr == nil {
err = c.client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Delete(ctx, vapName, metav1.DeleteOptions{})
@ -371,7 +373,7 @@ func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, nam
}
if observedVAP.ResourceVersion == "" {
err := validatingadmissionpolicy.BuildValidatingAdmissionPolicy(c.discoveryClient, observedVAP, policy)
err := validatingadmissionpolicy.BuildValidatingAdmissionPolicy(c.discoveryClient, observedVAP, policy, exceptions)
if err != nil {
c.updateClusterPolicyStatus(ctx, *policy, false, err.Error())
return err
@ -387,7 +389,7 @@ func (c *controller) reconcile(ctx context.Context, logger logr.Logger, key, nam
observedVAP,
c.client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies(),
func(observed *admissionregistrationv1alpha1.ValidatingAdmissionPolicy) error {
return validatingadmissionpolicy.BuildValidatingAdmissionPolicy(c.discoveryClient, observed, policy)
return validatingadmissionpolicy.BuildValidatingAdmissionPolicy(c.discoveryClient, observed, policy, exceptions)
})
if err != nil {
c.updateClusterPolicyStatus(ctx, *policy, false, err.Error())

View file

@ -5,6 +5,7 @@ import (
"slices"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
"github.com/kyverno/kyverno/pkg/clients/dclient"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
@ -18,6 +19,7 @@ func BuildValidatingAdmissionPolicy(
discoveryClient dclient.IDiscovery,
vap *admissionregistrationv1alpha1.ValidatingAdmissionPolicy,
cpol kyvernov1.PolicyInterface,
exceptions []kyvernov2.PolicyException,
) error {
// set owner reference
vap.OwnerReferences = []metav1.OwnerReference{
@ -73,6 +75,22 @@ func BuildValidatingAdmissionPolicy(
}
}
// convert the exceptions if exist
for _, exception := range exceptions {
match := exception.Spec.Match
if match.Any != nil {
if err := translateResourceFilters(discoveryClient, &matchResources, &excludeRules, match.Any, false); err != nil {
return err
}
}
if match.All != nil {
if err := translateResourceFilters(discoveryClient, &matchResources, &excludeRules, match.All, false); err != nil {
return err
}
}
}
// set policy spec
vap.Spec = admissionregistrationv1alpha1.ValidatingAdmissionPolicySpec{
MatchConstraints: &matchResources,

View file

@ -2,11 +2,57 @@ package validatingadmissionpolicy
import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
"github.com/kyverno/kyverno/ext/wildcard"
)
// CanGenerateVAP check if Kyverno policy can be translated to a Kubernetes ValidatingAdmissionPolicy
func CanGenerateVAP(spec *kyvernov1.Spec) (bool, string) {
// CanGenerateVAP check if Kyverno policy and a PolicyException can be translated to a Kubernetes ValidatingAdmissionPolicy
func CanGenerateVAP(spec *kyvernov1.Spec, exceptions []kyvernov2.PolicyException) (bool, string) {
var msg string
if ok, msg := checkPolicy(spec); !ok {
return false, msg
}
if ok, msg := checkExceptions(exceptions); !ok {
return false, msg
}
return true, msg
}
func checkExceptions(exceptions []kyvernov2.PolicyException) (bool, string) {
var msg string
for _, exception := range exceptions {
spec := exception.Spec
for _, exception := range spec.Exceptions {
if len(exception.RuleNames) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple ruleNames in PolicyException is not applicable."
return false, msg
}
}
if spec.Conditions != nil {
msg = "skip generating ValidatingAdmissionPolicy: Conditions in PolicyException is not applicable."
return false, msg
}
exclude := spec.Match
if ok, msg := checkResourceFilter(exclude.Any, false); !ok {
return false, msg
}
if len(exclude.All) > 1 {
msg = "skip generating ValidatingAdmissionPolicy: multiple 'all' in the PolicyException's match block is not applicable."
return false, msg
}
if ok, msg := checkResourceFilter(exclude.All, false); !ok {
return false, msg
}
}
return true, msg
}
func checkPolicy(spec *kyvernov1.Spec) (bool, string) {
var msg string
if ok, msg := checkRuleCount(spec); !ok {
return false, msg

View file

@ -4,9 +4,13 @@ import (
"encoding/json"
"testing"
"github.com/kyverno/kyverno/api/kyverno"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov2 "github.com/kyverno/kyverno/api/kyverno/v2"
kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1"
yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml"
"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func Test_Check_Resources(t *testing.T) {
@ -137,6 +141,232 @@ func Test_Check_Resources(t *testing.T) {
}
}
func Test_Check_Exception(t *testing.T) {
testCases := []struct {
name string
exceptions []kyvernov2.PolicyException
expected bool
}{
{
name: "exception-with-multiple-policies",
exceptions: []kyvernov2.PolicyException{
{
Spec: kyvernov2.PolicyExceptionSpec{
Exceptions: []kyvernov2.Exception{
{
PolicyName: "test-1",
RuleNames: []string{"rule-1"},
},
{
PolicyName: "test-2",
RuleNames: []string{"rule-2"},
},
},
},
},
},
expected: true,
},
{
name: "exception-with-multiple-rules",
exceptions: []kyvernov2.PolicyException{
{
Spec: kyvernov2.PolicyExceptionSpec{
Exceptions: []kyvernov2.Exception{
{
PolicyName: "test-1",
RuleNames: []string{"rule-1", "rule-2"},
},
},
},
},
},
expected: false,
},
{
name: "exception-with-multiple-rules-in-different-exceptions",
exceptions: []kyvernov2.PolicyException{
{
Spec: kyvernov2.PolicyExceptionSpec{
Exceptions: []kyvernov2.Exception{
{
PolicyName: "test-1",
RuleNames: []string{"rule-1", "rule-2"},
},
{
PolicyName: "test-2",
RuleNames: []string{"rule-1"},
},
},
},
},
},
expected: false,
},
{
name: "exception-with-conditions",
exceptions: []kyvernov2.PolicyException{
{
Spec: kyvernov2.PolicyExceptionSpec{
Exceptions: []kyvernov2.Exception{
{
PolicyName: "test-1",
RuleNames: []string{"rule-1"},
},
},
Conditions: &kyvernov2.AnyAllConditions{
AllConditions: []kyvernov2.Condition{
{
RawKey: &kyverno.Any{
Value: "{{ request.object.name }}",
},
Operator: kyvernov2.ConditionOperators["Equals"],
RawValue: &kyverno.Any{
Value: "dummy",
},
},
},
},
},
},
},
expected: false,
},
{
name: "exception-with-multiple-all",
exceptions: []kyvernov2.PolicyException{
{
Spec: kyvernov2.PolicyExceptionSpec{
Exceptions: []kyvernov2.Exception{
{
PolicyName: "test-1",
RuleNames: []string{"rule-1"},
},
},
Match: kyvernov2beta1.MatchResources{
All: kyvernov1.ResourceFilters{
kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{"Pod"},
Operations: []kyvernov1.AdmissionOperation{"CREATE"},
},
},
kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{"Pod"},
Operations: []kyvernov1.AdmissionOperation{"CREATE"},
},
},
},
},
},
},
},
expected: false,
},
{
name: "exception-with-namespace-selector",
exceptions: []kyvernov2.PolicyException{
{
Spec: kyvernov2.PolicyExceptionSpec{
Exceptions: []kyvernov2.Exception{
{
PolicyName: "test-1",
RuleNames: []string{"rule-1"},
},
},
Match: kyvernov2beta1.MatchResources{
Any: kyvernov1.ResourceFilters{
kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{"Pod"},
Operations: []kyvernov1.AdmissionOperation{"CREATE"},
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "critical",
},
},
},
},
},
},
},
},
},
expected: false,
},
{
name: "exception-with-object-selector",
exceptions: []kyvernov2.PolicyException{
{
Spec: kyvernov2.PolicyExceptionSpec{
Exceptions: []kyvernov2.Exception{
{
PolicyName: "test-1",
RuleNames: []string{"rule-1"},
},
},
Match: kyvernov2beta1.MatchResources{
Any: kyvernov1.ResourceFilters{
kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{"Pod"},
Operations: []kyvernov1.AdmissionOperation{"CREATE"},
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "critical",
},
},
},
},
},
},
},
},
},
expected: false,
},
{
name: "exception-with-multiple-any",
exceptions: []kyvernov2.PolicyException{
{
Spec: kyvernov2.PolicyExceptionSpec{
Exceptions: []kyvernov2.Exception{
{
PolicyName: "test-1",
RuleNames: []string{"rule-1"},
},
},
Match: kyvernov2beta1.MatchResources{
Any: kyvernov1.ResourceFilters{
kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{"Pod"},
Operations: []kyvernov1.AdmissionOperation{"CREATE"},
},
},
kyvernov1.ResourceFilter{
ResourceDescription: kyvernov1.ResourceDescription{
Kinds: []string{"Pod"},
Operations: []kyvernov1.AdmissionOperation{"CREATE"},
},
},
},
},
},
},
},
expected: true,
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
out, _ := checkExceptions(test.exceptions)
assert.Equal(t, out, test.expected)
})
}
}
func Test_Can_Generate_ValidatingAdmissionPolicy(t *testing.T) {
testCases := []struct {
name string
@ -618,7 +848,7 @@ func Test_Can_Generate_ValidatingAdmissionPolicy(t *testing.T) {
policies, _, _, err := yamlutils.GetPolicy([]byte(test.policy))
assert.NilError(t, err)
assert.Equal(t, 1, len(policies))
out, _ := CanGenerateVAP(policies[0].GetSpec())
out, _ := CanGenerateVAP(policies[0].GetSpec(), nil)
assert.Equal(t, out, test.expected)
})
}

View file

@ -457,7 +457,7 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
}
// check for CEL expression warnings in case of CEL subrules
if ok, _ := vaputils.CanGenerateVAP(spec); ok && client != nil {
if ok, _ := vaputils.CanGenerateVAP(spec, nil); ok && client != nil {
resolver := &resolver.ClientDiscoveryResolver{
Discovery: client.GetKubeClient().Discovery(),
}
@ -477,7 +477,7 @@ func Validate(policy, oldPolicy kyvernov1.PolicyInterface, client dclient.Interf
Name: policy.GetName(),
},
}
err = vaputils.BuildValidatingAdmissionPolicy(client.Discovery(), vap, policy)
err = vaputils.BuildValidatingAdmissionPolicy(client.Discovery(), vap, policy, nil)
if err != nil {
return nil, err
}

View file

@ -0,0 +1,23 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-with-an-exception-excluding-namespaces
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml
- name: step-02
try:
- apply:
file: exception.yaml
- name: step-03
try:
- assert:
file: validatingadmissionpolicy.yaml
- assert:
file: validatingadmissionpolicybinding.yaml

View file

@ -0,0 +1,18 @@
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: policy-exception
spec:
exceptions:
- policyName: disallow-host-path
ruleNames:
- host-path
match:
any:
- resources:
namespaces:
- testing-ns
- staging-ns
operations:
- CREATE
- UPDATE

View file

@ -1,23 +1,19 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path-t11
name: disallow-host-path
spec:
background: false
rules:
- name: host-path
match:
all:
any:
- resources:
kinds:
- Deployment
- StatefulSet
operations:
- CREATE
- UPDATE
selector:
matchLabels:
app: critical
validate:
validationFailureAction: Audit
cel:

View file

@ -0,0 +1,41 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: disallow-host-path
spec:
failurePolicy: Fail
matchConstraints:
excludeResourceRules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resourceNames:
- testing-ns
- staging-ns
resources:
- namespaces
resourceRules:
- apiGroups:
- apps
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- deployments
validations:
- expression: '!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume,
!has(volume.hostPath))'
message: HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath
must be unset.

View file

@ -0,0 +1,13 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path-binding
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: disallow-host-path
spec:
policyName: disallow-host-path
validationActions: [Audit, Warn]

View file

@ -0,0 +1,23 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-with-an-exception
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml
- name: step-02
try:
- apply:
file: exception.yaml
- name: step-03
try:
- assert:
file: validatingadmissionpolicy.yaml
- assert:
file: validatingadmissionpolicybinding.yaml

View file

@ -4,7 +4,7 @@ metadata:
name: policy-exception
spec:
exceptions:
- policyName: disallow-host-path-t11
- policyName: disallow-host-path
ruleNames:
- host-path
match:
@ -13,4 +13,7 @@ spec:
kinds:
- Deployment
names:
- important-tool*
- important-tool
operations:
- CREATE
- UPDATE

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,31 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
spec:
validationFailureAction: Audit
background: false
rules:
- name: host-path
match:
any:
- resources:
kinds:
- Deployment
- StatefulSet
- ReplicaSet
- DaemonSet
operations:
- CREATE
- UPDATE
namespaceSelector:
matchExpressions:
- key: type
operator: In
values:
- connector
validate:
cel:
expressions:
- expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))"
message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."

View file

@ -0,0 +1,49 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: disallow-host-path
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups:
- apps
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- deployments
- statefulsets
- replicasets
- daemonsets
namespaceSelector:
matchExpressions:
- key: type
operator: In
values:
- connector
excludeResourceRules:
- apiGroups:
- apps
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resourceNames:
- important-tool
resources:
- deployments
validations:
- expression: '!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume,
!has(volume.hostPath))'
message: HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath
must be unset.

View file

@ -0,0 +1,13 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path-binding
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: disallow-host-path
spec:
policyName: disallow-host-path
validationActions: [Audit, Warn]

View file

@ -0,0 +1,23 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-with-two-exceptions
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml
- name: step-02
try:
- apply:
file: exception.yaml
- name: step-03
try:
- assert:
file: validatingadmissionpolicy.yaml
- assert:
file: validatingadmissionpolicybinding.yaml

View file

@ -0,0 +1,39 @@
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: policy-exception-1
spec:
exceptions:
- policyName: disallow-host-path
ruleNames:
- host-path
match:
any:
- resources:
kinds:
- Deployment
names:
- important-tool
operations:
- CREATE
- UPDATE
---
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: policy-exception-2
spec:
exceptions:
- policyName: disallow-host-path
ruleNames:
- host-path
match:
any:
- resources:
kinds:
- StatefulSet
names:
- important-tool
operations:
- CREATE
- UPDATE

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,31 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
spec:
validationFailureAction: Audit
background: false
rules:
- name: host-path
match:
any:
- resources:
kinds:
- Deployment
- StatefulSet
- ReplicaSet
- DaemonSet
operations:
- CREATE
- UPDATE
namespaceSelector:
matchExpressions:
- key: type
operator: In
values:
- connector
validate:
cel:
expressions:
- expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))"
message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."

View file

@ -0,0 +1,50 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: disallow-host-path
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups:
- apps
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- deployments
- statefulsets
- replicasets
- daemonsets
namespaceSelector:
matchExpressions:
- key: type
operator: In
values:
- connector
excludeResourceRules:
- apiGroups:
- apps
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resourceNames:
- important-tool
resources:
- deployments
- statefulsets
validations:
- expression: '!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume,
!has(volume.hostPath))'
message: HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath
must be unset.

View file

@ -0,0 +1,13 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path-binding
ownerReferences:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: disallow-host-path
spec:
policyName: disallow-host-path
validationActions: [Audit, Warn]

View file

@ -2,7 +2,7 @@ apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-with-exceptions
name: cpol-with-exceptions-and-conditions
spec:
steps:
- name: step-01
@ -16,10 +16,6 @@ spec:
- apply:
file: exception.yaml
- name: step-03
try:
- sleep:
duration: 15s
- name: step-04
try:
- error:
file: validatingadmissionpolicy.yaml

View file

@ -0,0 +1,24 @@
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: policy-exception
spec:
exceptions:
- policyName: disallow-host-path
ruleNames:
- host-path
match:
any:
- resources:
kinds:
- Deployment
names:
- important-tool
operations:
- CREATE
- UPDATE
conditions:
any:
- key: "{{ request.object.metadata.labels.color || '' }}"
operator: Equals
value: red

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,31 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
spec:
validationFailureAction: Audit
background: false
rules:
- name: host-path
match:
any:
- resources:
kinds:
- Deployment
- StatefulSet
- ReplicaSet
- DaemonSet
operations:
- CREATE
- UPDATE
namespaceSelector:
matchExpressions:
- key: type
operator: In
values:
- connector
validate:
cel:
expressions:
- expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))"
message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."

View file

@ -0,0 +1,23 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-with-exception-and-namesapce-selector
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml
- name: step-02
try:
- apply:
file: exception.yaml
- name: step-03
try:
- error:
file: validatingadmissionpolicy.yaml
- error:
file: validatingadmissionpolicybinding.yaml

View file

@ -0,0 +1,23 @@
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: policy-exception
spec:
exceptions:
- policyName: disallow-host-path
ruleNames:
- host-path
match:
any:
- resources:
kinds:
- Deployment
operations:
- CREATE
- UPDATE
namespaceSelector:
matchExpressions:
- key: type
operator: In
values:
- connector

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,22 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
spec:
validationFailureAction: Audit
background: false
rules:
- name: host-path
match:
any:
- resources:
kinds:
- Deployment
operations:
- CREATE
- UPDATE
validate:
cel:
expressions:
- expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))"
message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."

View file

@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path
spec: {}

View file

@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path-binding
spec: {}

View file

@ -0,0 +1,23 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-with-exception-and-object-selector
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml
- name: step-02
try:
- apply:
file: exception.yaml
- name: step-03
try:
- error:
file: validatingadmissionpolicy.yaml
- error:
file: validatingadmissionpolicybinding.yaml

View file

@ -0,0 +1,20 @@
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: policy-exception
spec:
exceptions:
- policyName: disallow-host-path
ruleNames:
- host-path
match:
any:
- resources:
kinds:
- Deployment
operations:
- CREATE
- UPDATE
selector:
matchLabels:
app: critical

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,22 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
spec:
validationFailureAction: Audit
background: false
rules:
- name: host-path
match:
any:
- resources:
kinds:
- Deployment
operations:
- CREATE
- UPDATE
validate:
cel:
expressions:
- expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))"
message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."

View file

@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path
spec: {}

View file

@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path-binding
spec: {}

View file

@ -0,0 +1,23 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: cpol-with-exception-in-specific-namespace
spec:
steps:
- name: step-01
try:
- apply:
file: policy.yaml
- assert:
file: policy-assert.yaml
- name: step-02
try:
- apply:
file: exception.yaml
- name: step-03
try:
- error:
file: validatingadmissionpolicy.yaml
- error:
file: validatingadmissionpolicybinding.yaml

View file

@ -0,0 +1,20 @@
apiVersion: kyverno.io/v2
kind: PolicyException
metadata:
name: policy-exception
spec:
exceptions:
- policyName: disallow-host-path
ruleNames:
- host-path
match:
any:
- resources:
kinds:
- Deployment
operations:
- CREATE
- UPDATE
namespaces:
- testing-ns
- staging-ns

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,22 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-host-path
spec:
validationFailureAction: Audit
background: false
rules:
- name: host-path
match:
any:
- resources:
kinds:
- Deployment
operations:
- CREATE
- UPDATE
validate:
cel:
expressions:
- expression: "!has(object.spec.template.spec.volumes) || object.spec.template.spec.volumes.all(volume, !has(volume.hostPath))"
message: "HostPath volumes are forbidden. The field spec.template.spec.volumes[*].hostPath must be unset."

View file

@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicy
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path
spec: {}

View file

@ -0,0 +1,7 @@
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: ValidatingAdmissionPolicyBinding
metadata:
labels:
app.kubernetes.io/managed-by: kyverno
name: disallow-host-path-binding
spec: {}