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:
parent
3a69702b49
commit
25b7142ee0
47 changed files with 1044 additions and 31 deletions
|
@ -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())
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -1,7 +1,7 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: disallow-host-path-t11
|
||||
name: disallow-host-path
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
|
@ -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:
|
|
@ -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.
|
|
@ -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]
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: disallow-host-path
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
@ -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."
|
|
@ -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.
|
|
@ -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]
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: disallow-host-path
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
@ -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."
|
|
@ -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.
|
|
@ -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]
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: disallow-host-path
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
@ -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."
|
|
@ -3,5 +3,5 @@ kind: ValidatingAdmissionPolicy
|
|||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: kyverno
|
||||
name: disallow-host-path-t11
|
||||
spec: {}
|
||||
name: disallow-host-path
|
||||
spec: {}
|
|
@ -3,5 +3,5 @@ kind: ValidatingAdmissionPolicyBinding
|
|||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: kyverno
|
||||
name: disallow-host-path-t11-binding
|
||||
name: disallow-host-path-binding
|
||||
spec: {}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: disallow-host-path
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
@ -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."
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: admissionregistration.k8s.io/v1alpha1
|
||||
kind: ValidatingAdmissionPolicy
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: kyverno
|
||||
name: disallow-host-path
|
||||
spec: {}
|
|
@ -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: {}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: disallow-host-path
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
@ -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."
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: admissionregistration.k8s.io/v1alpha1
|
||||
kind: ValidatingAdmissionPolicy
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: kyverno
|
||||
name: disallow-host-path
|
||||
spec: {}
|
|
@ -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: {}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: disallow-host-path
|
||||
status:
|
||||
conditions:
|
||||
- reason: Succeeded
|
||||
status: "True"
|
||||
type: Ready
|
||||
|
|
@ -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."
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: admissionregistration.k8s.io/v1alpha1
|
||||
kind: ValidatingAdmissionPolicy
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: kyverno
|
||||
name: disallow-host-path
|
||||
spec: {}
|
|
@ -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: {}
|
Loading…
Add table
Reference in a new issue