From 61e4ca1c4a85d5e617c48626fa71a5bf4bc813e5 Mon Sep 17 00:00:00 2001 From: alichaddad Date: Sun, 29 May 2022 13:01:49 +0200 Subject: [PATCH] make agent and policies CRD backwards compatible --- PROJECT | 3 + api/v1/policy_types.go | 71 +--- api/v1/zz_generated.deepcopy.go | 142 +------- api/v2beta1/groupversion_info.go | 36 ++ api/v2beta1/policy_types.go | 164 +++++++++ api/v2beta1/zz_generated.deepcopy.go | 312 ++++++++++++++++++ .../crd/bases/pac.weave.works_policies.yaml | 130 ++++++++ .../crd/bases/pac.weave.works_policysets.yaml | 2 +- helm/crds/pac.weave.works_policies.yaml | 130 ++++++++ internal/entities/k8s/k8s.go | 8 +- internal/entities/k8s/k8s_test.go | 2 +- internal/policies/crd/crd.go | 6 +- main.go | 53 ++- 13 files changed, 841 insertions(+), 218 deletions(-) create mode 100644 api/v2beta1/groupversion_info.go create mode 100644 api/v2beta1/policy_types.go create mode 100644 api/v2beta1/zz_generated.deepcopy.go diff --git a/PROJECT b/PROJECT index 01d54e70..3ffc93c3 100644 --- a/PROJECT +++ b/PROJECT @@ -7,6 +7,9 @@ resources: - api: crdVersion: v1 namespaced: false + - api: + crdVersion: v2beta1 + namespaced: false domain: weave.works kind: Policy path: github.com/weaveworks/policy-agent/api/v1 diff --git a/api/v1/policy_types.go b/api/v1/policy_types.go index ec0e12ad..6c097af2 100644 --- a/api/v1/policy_types.go +++ b/api/v1/policy_types.go @@ -22,16 +22,11 @@ import ( ) const ( - PolicyResourceName = "policies" - PolicyKind = "Policy" - PolicySetResourceName = "policysets" - PolicySetKind = "PolicySet" + ResourceName = "policies" + Kind = "Policy" ) -var ( - PolicyGroupVersionResource = GroupVersion.WithResource(PolicyResourceName) - PolicySetGroupVersionResource = GroupVersion.WithResource(PolicySetResourceName) -) +var GroupVersionResource = GroupVersion.WithResource(ResourceName) // PolicyParameters defines a needed input in a policy type PolicyParameters struct { @@ -59,13 +54,6 @@ type PolicyTargets struct { Namespaces []string `json:"namespaces"` } -type PolicyStandard struct { - // ID idenitifer of the standarad - ID string `json:"id"` - // Controls standard controls - Controls []string `json:"controls,omitempty"` -} - // PolicySpec defines the desired state of Policy // It describes all that is needed to evaluate a resource against a rego code //+kubebuilder:object:generate:true @@ -77,8 +65,8 @@ type PolicySpec struct { // Code contains the policy rego code Code string `json:"code"` // +optional - // Enabled flag for third parties consumers that indicates if this policy should be considered or not - Enabled bool `json:"enabled,omitempty"` + // Enable specifies if this policy should be used for evaluation or not + Enable string `json:"enable,omitempty"` // +optional // Parameters are the inputs needed for the policy validation Parameters []PolicyParameters `json:"parameters,omitempty"` @@ -99,36 +87,22 @@ type PolicySpec struct { // Severity is a measure of the impact of that policy, can be low, medium or high Severity string `json:"severity"` // +optional - // Standards is a list of policy standards that this policy falls under - Standards []PolicyStandard `json:"standards"` -} - -type PolicySetFilters struct { - IDs []string `json:"ids,omitempty"` - Categories []string `json:"categories,omitempty"` - Severities []string `json:"severities,omitempty"` - Standards []string `json:"standards,omitempty"` - Tags []string `json:"tags,omitempty"` -} - -type PolicySetSpec struct { - ID string `json:"id"` - Name string `json:"name"` - Filters PolicySetFilters `json:"filters"` + // Controls is a list of policy controls that this policy falls under + Controls []string `json:"controls,omitempty"` } -// +kubebuilder:object:root=true +//+kubebuilder:object:root=true // +kubebuilder:resource:scope=Cluster // Policy is the Schema for the policies API type Policy struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec PolicySpec `json:"spec,omitempty"` + + Spec PolicySpec `json:"spec,omitempty"` } -// +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster +//+kubebuilder:object:root=true // PolicyList contains a list of Policy type PolicyList struct { @@ -137,27 +111,6 @@ type PolicyList struct { Items []Policy `json:"items"` } -// +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster - -// PolicySet is the Schema for the policysets API -type PolicySet struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec PolicySetSpec `json:"spec,omitempty"` -} - -// +kubebuilder:object:root=true -// +kubebuilder:resource:scope=Cluster - -// PolicySetList contains a list of PolicySet -type PolicySetList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []PolicySet `json:"items"` -} - func init() { - SchemeBuilder.Register(&Policy{}, &PolicyList{}, &PolicySet{}, &PolicySetList{}) + SchemeBuilder.Register(&Policy{}, &PolicyList{}) } diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 321397a0..c51be8b8 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -104,120 +104,6 @@ func (in *PolicyParameters) DeepCopy() *PolicyParameters { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PolicySet) DeepCopyInto(out *PolicySet) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySet. -func (in *PolicySet) DeepCopy() *PolicySet { - if in == nil { - return nil - } - out := new(PolicySet) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PolicySet) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PolicySetFilters) DeepCopyInto(out *PolicySetFilters) { - *out = *in - if in.IDs != nil { - in, out := &in.IDs, &out.IDs - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Categories != nil { - in, out := &in.Categories, &out.Categories - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Severities != nil { - in, out := &in.Severities, &out.Severities - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Standards != nil { - in, out := &in.Standards, &out.Standards - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Tags != nil { - in, out := &in.Tags, &out.Tags - *out = make([]string, len(*in)) - copy(*out, *in) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySetFilters. -func (in *PolicySetFilters) DeepCopy() *PolicySetFilters { - if in == nil { - return nil - } - out := new(PolicySetFilters) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PolicySetList) DeepCopyInto(out *PolicySetList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PolicySet, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySetList. -func (in *PolicySetList) DeepCopy() *PolicySetList { - if in == nil { - return nil - } - out := new(PolicySetList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PolicySetList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PolicySetSpec) DeepCopyInto(out *PolicySetSpec) { - *out = *in - in.Filters.DeepCopyInto(&out.Filters) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySetSpec. -func (in *PolicySetSpec) DeepCopy() *PolicySetSpec { - if in == nil { - return nil - } - out := new(PolicySetSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PolicySpec) DeepCopyInto(out *PolicySpec) { *out = *in @@ -234,28 +120,6 @@ func (in *PolicySpec) DeepCopyInto(out *PolicySpec) { *out = make([]string, len(*in)) copy(*out, *in) } - if in.Standards != nil { - in, out := &in.Standards, &out.Standards - *out = make([]PolicyStandard, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySpec. -func (in *PolicySpec) DeepCopy() *PolicySpec { - if in == nil { - return nil - } - out := new(PolicySpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PolicyStandard) DeepCopyInto(out *PolicyStandard) { - *out = *in if in.Controls != nil { in, out := &in.Controls, &out.Controls *out = make([]string, len(*in)) @@ -263,12 +127,12 @@ func (in *PolicyStandard) DeepCopyInto(out *PolicyStandard) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyStandard. -func (in *PolicyStandard) DeepCopy() *PolicyStandard { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySpec. +func (in *PolicySpec) DeepCopy() *PolicySpec { if in == nil { return nil } - out := new(PolicyStandard) + out := new(PolicySpec) in.DeepCopyInto(out) return out } diff --git a/api/v2beta1/groupversion_info.go b/api/v2beta1/groupversion_info.go new file mode 100644 index 00000000..a07b1910 --- /dev/null +++ b/api/v2beta1/groupversion_info.go @@ -0,0 +1,36 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1 contains API Schema definitions for the v1 API group +//+kubebuilder:object:generate=true +//+groupName=pac.weave.works +package v2beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "pac.weave.works", Version: "v2beta1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v2beta1/policy_types.go b/api/v2beta1/policy_types.go new file mode 100644 index 00000000..9959e817 --- /dev/null +++ b/api/v2beta1/policy_types.go @@ -0,0 +1,164 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2beta1 + +import ( + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + PolicyResourceName = "policies" + PolicyKind = "Policy" + PolicySetResourceName = "policysets" + PolicySetKind = "PolicySet" +) + +var ( + PolicyGroupVersionResource = GroupVersion.WithResource(PolicyResourceName) + PolicySetGroupVersionResource = GroupVersion.WithResource(PolicySetResourceName) +) + +// PolicyParameters defines a needed input in a policy +type PolicyParameters struct { + // Name is a descriptive name of a policy parameter + Name string `json:"name"` + // Type is the type of that parameter, integer, string,... + Type string `json:"type"` + // Required specifies if this is a necessary value or not + Required bool `json:"required"` + // +optional + // Value is the value for that parameter + Value *apiextensionsv1.JSON `json:"value,omitempty"` +} + +// PolicyTargets are filters used to determine which resources should be evaluated against a policy +type PolicyTargets struct { + // Kinds is a list of Kubernetes kinds that are supported by this policy + Kinds []string `json:"kinds"` + // +optional + // Labels is a list of Kubernetes labels that are needed to evaluate the policy against a resource + // this filter is statisfied if only one label existed, using * for value make it so it will match if the key exists regardless of its value + Labels []map[string]string `json:"labels"` + // +optional + // Namespaces is a list of Kubernetes namespaces that a resource needs to be a part of to evaluate against this policy + Namespaces []string `json:"namespaces"` +} + +type PolicyStandard struct { + // ID idenitifer of the standarad + ID string `json:"id"` + // Controls standard controls + Controls []string `json:"controls,omitempty"` +} + +// PolicySpec defines the desired state of Policy +// It describes all that is needed to evaluate a resource against a rego code +//+kubebuilder:object:generate:true +type PolicySpec struct { + // Name is the policy name + Name string `json:"name"` + // ID is the policy unique identifier + ID string `json:"id"` + // Code contains the policy rego code + Code string `json:"code"` + // +optional + // Enabled flag for third parties consumers that indicates if this policy should be considered or not + Enabled bool `json:"enabled,omitempty"` + // +optional + // Parameters are the inputs needed for the policy validation + Parameters []PolicyParameters `json:"parameters,omitempty"` + // +optional + // Targets describes the required metadata that needs to be matched to evaluate a resource against the policy + // all values specified need to exist in the resource to be considered for evaluation + Targets PolicyTargets `json:"targets,omitempty"` + // Description is a summary of what that policy validates + Description string `json:"description"` + // HowToSolve is a description of the steps required to solve the issues reported by the policy + HowToSolve string `json:"how_to_solve"` + // Category specifies under which grouping this policy should be included + Category string `json:"category"` + // +optional + // Tags is a list of tags associated with that policy + Tags []string `json:"tags,omitempty"` + // +kubebuilder:validation:Enum=low;medium;high + // Severity is a measure of the impact of that policy, can be low, medium or high + Severity string `json:"severity"` + // +optional + // Standards is a list of policy standards that this policy falls under + Standards []PolicyStandard `json:"standards"` +} + +type PolicySetFilters struct { + IDs []string `json:"ids,omitempty"` + Categories []string `json:"categories,omitempty"` + Severities []string `json:"severities,omitempty"` + Standards []string `json:"standards,omitempty"` + Tags []string `json:"tags,omitempty"` +} + +type PolicySetSpec struct { + ID string `json:"id"` + Name string `json:"name"` + Filters PolicySetFilters `json:"filters"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:resource:scope=Cluster +//+kubebuilder:storageversion + +// Policy is the Schema for the policies API +type Policy struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec PolicySpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster + +// PolicyList contains a list of Policy +type PolicyList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Policy `json:"items"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster + +// PolicySet is the Schema for the policysets API +type PolicySet struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PolicySetSpec `json:"spec,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster + +// PolicySetList contains a list of PolicySet +type PolicySetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PolicySet `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Policy{}, &PolicyList{}, &PolicySet{}, &PolicySetList{}) +} diff --git a/api/v2beta1/zz_generated.deepcopy.go b/api/v2beta1/zz_generated.deepcopy.go new file mode 100644 index 00000000..ca4c58e6 --- /dev/null +++ b/api/v2beta1/zz_generated.deepcopy.go @@ -0,0 +1,312 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v2beta1 + +import ( + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Policy) DeepCopyInto(out *Policy) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Policy. +func (in *Policy) DeepCopy() *Policy { + if in == nil { + return nil + } + out := new(Policy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Policy) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicyList) DeepCopyInto(out *PolicyList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Policy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyList. +func (in *PolicyList) DeepCopy() *PolicyList { + if in == nil { + return nil + } + out := new(PolicyList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PolicyList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicyParameters) DeepCopyInto(out *PolicyParameters) { + *out = *in + if in.Value != nil { + in, out := &in.Value, &out.Value + *out = new(v1.JSON) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyParameters. +func (in *PolicyParameters) DeepCopy() *PolicyParameters { + if in == nil { + return nil + } + out := new(PolicyParameters) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicySet) DeepCopyInto(out *PolicySet) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySet. +func (in *PolicySet) DeepCopy() *PolicySet { + if in == nil { + return nil + } + out := new(PolicySet) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PolicySet) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicySetFilters) DeepCopyInto(out *PolicySetFilters) { + *out = *in + if in.IDs != nil { + in, out := &in.IDs, &out.IDs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Categories != nil { + in, out := &in.Categories, &out.Categories + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Severities != nil { + in, out := &in.Severities, &out.Severities + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Standards != nil { + in, out := &in.Standards, &out.Standards + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySetFilters. +func (in *PolicySetFilters) DeepCopy() *PolicySetFilters { + if in == nil { + return nil + } + out := new(PolicySetFilters) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicySetList) DeepCopyInto(out *PolicySetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PolicySet, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySetList. +func (in *PolicySetList) DeepCopy() *PolicySetList { + if in == nil { + return nil + } + out := new(PolicySetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PolicySetList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicySetSpec) DeepCopyInto(out *PolicySetSpec) { + *out = *in + in.Filters.DeepCopyInto(&out.Filters) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySetSpec. +func (in *PolicySetSpec) DeepCopy() *PolicySetSpec { + if in == nil { + return nil + } + out := new(PolicySetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicySpec) DeepCopyInto(out *PolicySpec) { + *out = *in + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + *out = make([]PolicyParameters, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Targets.DeepCopyInto(&out.Targets) + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Standards != nil { + in, out := &in.Standards, &out.Standards + *out = make([]PolicyStandard, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicySpec. +func (in *PolicySpec) DeepCopy() *PolicySpec { + if in == nil { + return nil + } + out := new(PolicySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicyStandard) DeepCopyInto(out *PolicyStandard) { + *out = *in + if in.Controls != nil { + in, out := &in.Controls, &out.Controls + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyStandard. +func (in *PolicyStandard) DeepCopy() *PolicyStandard { + if in == nil { + return nil + } + out := new(PolicyStandard) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PolicyTargets) DeepCopyInto(out *PolicyTargets) { + *out = *in + if in.Kinds != nil { + in, out := &in.Kinds, &out.Kinds + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make([]map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PolicyTargets. +func (in *PolicyTargets) DeepCopy() *PolicyTargets { + if in == nil { + return nil + } + out := new(PolicyTargets) + in.DeepCopyInto(out) + return out +} diff --git a/config/crd/bases/pac.weave.works_policies.yaml b/config/crd/bases/pac.weave.works_policies.yaml index 38fdd604..1fe54c10 100644 --- a/config/crd/bases/pac.weave.works_policies.yaml +++ b/config/crd/bases/pac.weave.works_policies.yaml @@ -16,6 +16,136 @@ spec: scope: Cluster versions: - name: v1 + schema: + openAPIV3Schema: + description: Policy is the Schema for the policies API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PolicySpec defines the desired state of Policy It describes + all that is needed to evaluate a resource against a rego code + properties: + category: + description: Category specifies under which grouping this policy should + be included + type: string + code: + description: Code contains the policy rego code + type: string + controls: + description: Controls is a list of policy controls that this policy + falls under + items: + type: string + type: array + description: + description: Description is a summary of what that policy validates + type: string + enable: + description: Enable specifies if this policy should be used for evaluation + or not + type: string + how_to_solve: + description: HowToSolve is a description of the steps required to + solve the issues reported by the policy + type: string + id: + description: ID is the policy unique identifier + type: string + name: + description: Name is the policy name + type: string + parameters: + description: Parameters are the inputs needed for the policy validation + items: + description: PolicyParameters defines a needed input in a policy + properties: + name: + description: Name is a descriptive name of a policy parameter + type: string + required: + description: Required specifies if this is a necessary value + or not + type: boolean + type: + description: Type is the type of that parameter, integer, string,... + type: string + value: + description: Value is the value for that parameter + x-kubernetes-preserve-unknown-fields: true + required: + - name + - required + - type + type: object + type: array + severity: + description: Severity is a measure of the impact of that policy, can + be low, medium or high + enum: + - low + - medium + - high + type: string + tags: + description: Tags is a list of tags associated with that policy + items: + type: string + type: array + targets: + description: Targets describes the required metadata that needs to + be matched to evaluate a resource against the policy all values + specified need to exist in the resource to be considered for evaluation + properties: + kinds: + description: Kinds is a list of Kubernetes kinds that are supported + by this policy + items: + type: string + type: array + labels: + description: Labels is a list of Kubernetes labels that are needed + to evaluate the policy against a resource this filter is statisfied + if only one label existed, using * for value make it so it will + match if the key exists regardless of its value + items: + additionalProperties: + type: string + type: object + type: array + namespaces: + description: Namespaces is a list of Kubernetes namespaces that + a resource needs to be a part of to evaluate against this policy + items: + type: string + type: array + required: + - kinds + type: object + required: + - category + - code + - description + - how_to_solve + - id + - name + - severity + type: object + type: object + served: true + storage: false + - name: v2beta1 schema: openAPIV3Schema: description: Policy is the Schema for the policies API diff --git a/config/crd/bases/pac.weave.works_policysets.yaml b/config/crd/bases/pac.weave.works_policysets.yaml index 8c968998..d1b5fb00 100644 --- a/config/crd/bases/pac.weave.works_policysets.yaml +++ b/config/crd/bases/pac.weave.works_policysets.yaml @@ -15,7 +15,7 @@ spec: singular: policyset scope: Cluster versions: - - name: v1 + - name: v2beta1 schema: openAPIV3Schema: description: PolicySet is the Schema for the policysets API diff --git a/helm/crds/pac.weave.works_policies.yaml b/helm/crds/pac.weave.works_policies.yaml index 38fdd604..1fe54c10 100644 --- a/helm/crds/pac.weave.works_policies.yaml +++ b/helm/crds/pac.weave.works_policies.yaml @@ -16,6 +16,136 @@ spec: scope: Cluster versions: - name: v1 + schema: + openAPIV3Schema: + description: Policy is the Schema for the policies API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PolicySpec defines the desired state of Policy It describes + all that is needed to evaluate a resource against a rego code + properties: + category: + description: Category specifies under which grouping this policy should + be included + type: string + code: + description: Code contains the policy rego code + type: string + controls: + description: Controls is a list of policy controls that this policy + falls under + items: + type: string + type: array + description: + description: Description is a summary of what that policy validates + type: string + enable: + description: Enable specifies if this policy should be used for evaluation + or not + type: string + how_to_solve: + description: HowToSolve is a description of the steps required to + solve the issues reported by the policy + type: string + id: + description: ID is the policy unique identifier + type: string + name: + description: Name is the policy name + type: string + parameters: + description: Parameters are the inputs needed for the policy validation + items: + description: PolicyParameters defines a needed input in a policy + properties: + name: + description: Name is a descriptive name of a policy parameter + type: string + required: + description: Required specifies if this is a necessary value + or not + type: boolean + type: + description: Type is the type of that parameter, integer, string,... + type: string + value: + description: Value is the value for that parameter + x-kubernetes-preserve-unknown-fields: true + required: + - name + - required + - type + type: object + type: array + severity: + description: Severity is a measure of the impact of that policy, can + be low, medium or high + enum: + - low + - medium + - high + type: string + tags: + description: Tags is a list of tags associated with that policy + items: + type: string + type: array + targets: + description: Targets describes the required metadata that needs to + be matched to evaluate a resource against the policy all values + specified need to exist in the resource to be considered for evaluation + properties: + kinds: + description: Kinds is a list of Kubernetes kinds that are supported + by this policy + items: + type: string + type: array + labels: + description: Labels is a list of Kubernetes labels that are needed + to evaluate the policy against a resource this filter is statisfied + if only one label existed, using * for value make it so it will + match if the key exists regardless of its value + items: + additionalProperties: + type: string + type: object + type: array + namespaces: + description: Namespaces is a list of Kubernetes namespaces that + a resource needs to be a part of to evaluate against this policy + items: + type: string + type: array + required: + - kinds + type: object + required: + - category + - code + - description + - how_to_solve + - id + - name + - severity + type: object + type: object + served: true + storage: false + - name: v2beta1 schema: openAPIV3Schema: description: Policy is the Schema for the policies API diff --git a/internal/entities/k8s/k8s.go b/internal/entities/k8s/k8s.go index 1b5a4ce7..9b44ffdb 100644 --- a/internal/entities/k8s/k8s.go +++ b/internal/entities/k8s/k8s.go @@ -7,7 +7,7 @@ import ( "github.com/MagalixTechnologies/core/logger" "github.com/MagalixTechnologies/policy-core/domain" - pacv1 "github.com/weaveworks/policy-agent/api/v1" + pacv2 "github.com/weaveworks/policy-agent/api/v2beta1" "github.com/weaveworks/policy-agent/internal/clients/kube" corev1 "k8s.io/api/core/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -76,8 +76,8 @@ func getValidateRules(ctx context.Context, kubeClient *kube.KubeClient) ([]rules cache.apiGroups[rule.APIGroups[k]] = struct{}{} } rulesCaches = append(rulesCaches, cache) - checkPoliciesResource := checkAllowed(pacv1.PolicyResourceName, cache.resources) - checkPoliciesGroup := checkAllowed(pacv1.GroupVersion.Group, cache.apiGroups) + checkPoliciesResource := checkAllowed(pacv2.PolicyResourceName, cache.resources) + checkPoliciesGroup := checkAllowed(pacv2.GroupVersion.Group, cache.apiGroups) if checkPoliciesResource && checkPoliciesGroup { foundPolicicesRule = true } @@ -136,7 +136,7 @@ func GetEntitiesSources(ctx context.Context, kubeClient *kube.KubeClient) ([]dom Group: groupVersion.Group, Version: groupVersion.Version, Resource: apiResource.Name} - if resource.String() == pacv1.PolicyGroupVersionResource.String() { + if resource.String() == pacv2.PolicyGroupVersionResource.String() { continue } diff --git a/internal/entities/k8s/k8s_test.go b/internal/entities/k8s/k8s_test.go index 667b1a43..8af9ddc1 100644 --- a/internal/entities/k8s/k8s_test.go +++ b/internal/entities/k8s/k8s_test.go @@ -313,7 +313,7 @@ func TestGetEntitiesSources(t *testing.T) { discoveryClient: &DiscoveryMock{ ApiList: []*meta.APIResourceList{ { - GroupVersion: "pac.weave.works/v1", + GroupVersion: "pac.weave.works/v2beta1", APIResources: []meta.APIResource{ { Name: "policies", diff --git a/internal/policies/crd/crd.go b/internal/policies/crd/crd.go index 8d44385d..4d7aa2e4 100644 --- a/internal/policies/crd/crd.go +++ b/internal/policies/crd/crd.go @@ -7,7 +7,7 @@ import ( "github.com/MagalixTechnologies/core/logger" "github.com/MagalixTechnologies/policy-core/domain" - pacv1 "github.com/weaveworks/policy-agent/api/v1" + pacv2 "github.com/weaveworks/policy-agent/api/v2beta1" v1 "k8s.io/api/core/v1" ctrl "sigs.k8s.io/controller-runtime" ctrlCache "sigs.k8s.io/controller-runtime/pkg/cache" @@ -30,7 +30,7 @@ func (p *PoliciesWatcher) SetPolicySet(name string) { // GetAll returns all policies, implements github.com/MagalixTechnologies/policy-core/domain.PoliciesSource func (p *PoliciesWatcher) GetAll(ctx context.Context) ([]domain.Policy, error) { - policiesCRD := &pacv1.PolicyList{} + policiesCRD := &pacv2.PolicyList{} err := p.cache.List(ctx, policiesCRD, &client.ListOptions{}) if err != nil { @@ -111,7 +111,7 @@ func (p *PoliciesWatcher) GetAll(ctx context.Context) ([]domain.Policy, error) { } func (p *PoliciesWatcher) GetPolicySet(ctx context.Context, id string) (*domain.PolicySet, error) { - policySet := pacv1.PolicySet{} + policySet := pacv2.PolicySet{} err := p.cache.Get(ctx, client.ObjectKey{Name: id}, &policySet) if err != nil { return nil, err diff --git a/main.go b/main.go index b9402727..71713aa6 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,7 @@ import ( "github.com/MagalixTechnologies/uuid-go" "github.com/fluxcd/pkg/runtime/events" "github.com/urfave/cli/v2" - pacv1 "github.com/weaveworks/policy-agent/api/v1" + pacv2 "github.com/weaveworks/policy-agent/api/v2beta1" "github.com/weaveworks/policy-agent/internal/admission" "github.com/weaveworks/policy-agent/internal/auditor" "github.com/weaveworks/policy-agent/internal/clients/gateway" @@ -75,6 +75,10 @@ type Config struct { MetricsAddr string AuditPolicySet string AdmissionPolicySet string + + //backwards compatibility only + DisableAdmission bool + DisableAudit bool } var ( @@ -213,12 +217,29 @@ func main() { Destination: &config.AdmissionPolicySet, EnvVars: []string{"AGENT_ADMISSION_POLICY_SET"}, }, + // deprecated, for backwards compatibility + &cli.BoolFlag{ + Name: "disable-admission", + Usage: "disables admission control", + Destination: &config.DisableAdmission, + Value: false, + EnvVars: []string{"AGENT_DISABLE_ADMISSION"}, + }, + // deprecated, for backwards compatibility + &cli.BoolFlag{ + Name: "disable-audit", + Usage: "disables cluster periodical audit", + Destination: &config.DisableAudit, + Value: false, + EnvVars: []string{"AGENT_DISABLE_AUDIT"}, + }, } app.Before = func(c *cli.Context) error { - if !config.EnableAdmission && !config.EnableAudit { - return errors.New("agent needs to be run with at least one mode of operation") - } + //@TODO this should be the correct behavior after the initial backwards compatible release + // if !config.EnableAdmission && !config.EnableAudit { + // return errors.New("agent needs to be run with at least one mode of operation") + // } switch config.LogLevel { case "info": @@ -239,6 +260,16 @@ func main() { app.Action = func(contextCli *cli.Context) error { logger.Infow("initializing Policy Agent", "build", build) logger.Infof("config: %+v", config) + enableAdmission := true + enableAudit := true + + if config.EnableAdmission || config.EnableAudit { + enableAdmission = config.EnableAdmission + enableAudit = config.EnableAudit + } else if config.DisableAdmission || config.DisableAudit { + enableAdmission = !config.DisableAdmission + enableAudit = !config.DisableAudit + } var kubeConfig *rest.Config var err error @@ -251,7 +282,7 @@ func main() { return fmt.Errorf("failed to load Kubernetes config: %w", err) } - err = pacv1.AddToScheme(scheme) + err = pacv2.AddToScheme(scheme) if err != nil { return fmt.Errorf("failed to add policy crd to scheme: %w", err) } @@ -316,7 +347,7 @@ func main() { return err } defer fluxNotificationSink.Stop() - if config.EnableAudit { + if enableAudit { logger.Warn("ignoring flux notifications sink for audit validation") } admissionSinks = append(admissionSinks, fluxNotificationSink) @@ -329,7 +360,7 @@ func main() { return err } defer k8sEventSink.Stop() - if config.EnableAudit { + if enableAudit { logger.Warn("ignoring kubernetes events sink for audit validation") } admissionSinks = append(admissionSinks, k8sEventSink) @@ -341,14 +372,14 @@ func main() { if err != nil { return err } - if config.EnableAudit { + if enableAudit { gatewaySink, err := initSaaSSink(contextCli.Context, mgr, kubeClient, config, gateway, packet.PacketPolicyValidationAudit) if err != nil { return err } auditSinks = append(auditSinks, gatewaySink) } - if config.EnableAdmission { + if enableAdmission { gatewaySink, err := initSaaSSink(contextCli.Context, mgr, kubeClient, config, gateway, packet.PacketPolicyValidationAdmission) if err != nil { return err @@ -357,7 +388,7 @@ func main() { } } - if config.EnableAudit { + if enableAudit { logger.Info("starting audit policies watcher") policiesSource, err := crd.NewPoliciesWatcher(contextCli.Context, mgr) @@ -383,7 +414,7 @@ func main() { auditController.Audit(auditor.AuditEventTypeInitial, nil) } - if config.EnableAdmission { + if enableAdmission { logger.Info("starting admission policies watcher") policiesSource, err := crd.NewPoliciesWatcher(contextCli.Context, mgr)