diff --git a/Makefile b/Makefile index 8f7d75e..008f991 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,7 @@ lint: crds: mkdir -p test/crd/ curl -fsL -o test/crd/ciliumnetworkpolicies.yaml https://github.com/cilium/cilium/raw/$(CILIUM_VERSION)/pkg/k8s/apis/cilium.io/client/crds/v2/ciliumnetworkpolicies.yaml + curl -fsL -o test/crd/ciliumclusterwidenetworkpolicies.yaml https://github.com/cilium/cilium/raw/$(CILIUM_VERSION)/pkg/k8s/apis/cilium.io/client/crds/v2/ciliumclusterwidenetworkpolicies.yaml .PHONY: test test: manifests generate fmt vet crds setup-envtest ## Run tests. diff --git a/PROJECT b/PROJECT index ae03086..8bbcb1e 100644 --- a/PROJECT +++ b/PROJECT @@ -6,13 +6,13 @@ repo: github.com/cybozu-go/tenet resources: - api: crdVersion: v1 - namespaced: true + namespaced: false controller: true domain: cybozu.io group: tenet kind: NetworkPolicyTemplate - path: github.com/cybozu-go/tenet/api/v1beta1 - version: v1beta1 + path: github.com/cybozu-go/tenet/api/v1beta2 + version: v1beta2 - api: crdVersion: v1 namespaced: true diff --git a/api/v1beta1/groupversion_info.go b/api/v1beta2/groupversion_info.go similarity index 97% rename from api/v1beta1/groupversion_info.go rename to api/v1beta2/groupversion_info.go index d62dc46..cd0ff0b 100644 --- a/api/v1beta1/groupversion_info.go +++ b/api/v1beta2/groupversion_info.go @@ -17,7 +17,7 @@ limitations under the License. // Package v1beta1 contains API Schema definitions for the tenet v1beta1 API group //+kubebuilder:object:generate=true //+groupName=tenet.cybozu.io -package v1beta1 +package v1beta2 import ( "k8s.io/apimachinery/pkg/runtime/schema" @@ -26,7 +26,7 @@ import ( var ( // GroupVersion is group version used to register these objects. - GroupVersion = schema.GroupVersion{Group: "tenet.cybozu.io", Version: "v1beta1"} + GroupVersion = schema.GroupVersion{Group: "tenet.cybozu.io", Version: "v1beta2"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/api/v1beta1/networkpolicyadmissionrule_types.go b/api/v1beta2/networkpolicyadmissionrule_types.go similarity index 98% rename from api/v1beta1/networkpolicyadmissionrule_types.go rename to api/v1beta2/networkpolicyadmissionrule_types.go index 144e829..8d46095 100644 --- a/api/v1beta1/networkpolicyadmissionrule_types.go +++ b/api/v1beta2/networkpolicyadmissionrule_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1beta1 +package v1beta2 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -62,6 +62,7 @@ type NetworkPolicyAdmissionRuleForbiddenIPRanges struct { //+kubebuilder:object:root=true //+kubebuilder:resource:scope=Cluster //+kubebuilder:subresource:status +//+kubebuilder:storageversion // NetworkPolicyAdmissionRule is the Schema for the networkpolicyadmissionrules API. type NetworkPolicyAdmissionRule struct { diff --git a/api/v1beta1/networkpolicytemplate_types.go b/api/v1beta2/networkpolicytemplate_types.go similarity index 90% rename from api/v1beta1/networkpolicytemplate_types.go rename to api/v1beta2/networkpolicytemplate_types.go index 73fd9a6..ba7e70b 100644 --- a/api/v1beta1/networkpolicytemplate_types.go +++ b/api/v1beta2/networkpolicytemplate_types.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1beta1 +package v1beta2 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -31,6 +31,9 @@ const ( // NetworkPolicyTemplateSpec defines the desired state of NetworkPolicyTemplate. type NetworkPolicyTemplateSpec struct { + // ClusterWide indicates whether the generated templates are clusterwide templates + //+kubebuilder:default=false + ClusterWide bool `json:"clusterwide,omitempty"` // PolicyTemplate is a template for creating NetworkPolicies PolicyTemplate string `json:"policyTemplate"` } @@ -38,6 +41,7 @@ type NetworkPolicyTemplateSpec struct { //+kubebuilder:object:root=true //+kubebuilder:resource:scope=Cluster //+kubebuilder:subresource:status +//+kubebuilder:storageversion // NetworkPolicyTemplate is the Schema for the networkpolicytemplates API. type NetworkPolicyTemplate struct { diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go similarity index 99% rename from api/v1beta1/zz_generated.deepcopy.go rename to api/v1beta2/zz_generated.deepcopy.go index ac7d20f..4200fcc 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -19,7 +19,7 @@ limitations under the License. // Code generated by controller-gen. DO NOT EDIT. -package v1beta1 +package v1beta2 import ( runtime "k8s.io/apimachinery/pkg/runtime" diff --git a/charts/tenet/templates/generated/crds/tenet.cybozu.io_crds.yaml b/charts/tenet/templates/generated/crds/tenet.cybozu.io_crds.yaml index b887e7b..0ae4c83 100644 --- a/charts/tenet/templates/generated/crds/tenet.cybozu.io_crds.yaml +++ b/charts/tenet/templates/generated/crds/tenet.cybozu.io_crds.yaml @@ -30,7 +30,7 @@ spec: singular: networkpolicyadmissionrule scope: Cluster versions: - - name: v1beta1 + - name: v1beta2 schema: openAPIV3Schema: description: NetworkPolicyAdmissionRule is the Schema for the networkpolicyadmissionrules @@ -136,7 +136,7 @@ spec: singular: networkpolicytemplate scope: Cluster versions: - - name: v1beta1 + - name: v1beta2 schema: openAPIV3Schema: description: NetworkPolicyTemplate is the Schema for the networkpolicytemplates @@ -157,6 +157,11 @@ spec: spec: description: Spec is the spec for the NetworkPolicyTemplate properties: + clusterwide: + default: false + description: ClusterWide indicates whether the generated templates + are clusterwide templates + type: boolean policyTemplate: description: PolicyTemplate is a template for creating NetworkPolicies type: string diff --git a/charts/tenet/templates/generated/generated.yaml b/charts/tenet/templates/generated/generated.yaml index ca5e1d4..cc6b580 100644 --- a/charts/tenet/templates/generated/generated.yaml +++ b/charts/tenet/templates/generated/generated.yaml @@ -71,6 +71,17 @@ rules: - get - list - watch +- apiGroups: + - cilium.io + resources: + - ciliumclusterwidenetworkpolicies + verbs: + - create + - delete + - get + - list + - update + - watch - apiGroups: - cilium.io resources: @@ -274,14 +285,14 @@ webhooks: service: name: '{{ template "tenet.fullname" . }}-webhook-service' namespace: '{{ .Release.Namespace }}' - path: /validate-tenet-cybozu-io-v1beta1-networkpolicyadmissionrule + path: /validate-tenet-cybozu-io-v1beta2-networkpolicyadmissionrule failurePolicy: Fail name: vnetworkpolicyadmissionrule.kb.io rules: - apiGroups: - tenet.cybozu.io apiVersions: - - v1beta1 + - v1beta2 operations: - CREATE - UPDATE diff --git a/cmd/tenet-controller/main.go b/cmd/tenet-controller/main.go index d09e0bb..653ae84 100644 --- a/cmd/tenet-controller/main.go +++ b/cmd/tenet-controller/main.go @@ -33,7 +33,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" "github.com/cybozu-go/tenet/controllers" "github.com/cybozu-go/tenet/hooks" //+kubebuilder:scaffold:imports @@ -46,7 +46,7 @@ var ( func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(tenetv1beta1.AddToScheme(scheme)) + utilruntime.Must(tenetv1beta2.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } diff --git a/config/crd/bases/tenet.cybozu.io_networkpolicyadmissionrules.yaml b/config/crd/bases/tenet.cybozu.io_networkpolicyadmissionrules.yaml index 3366b88..cf47d81 100644 --- a/config/crd/bases/tenet.cybozu.io_networkpolicyadmissionrules.yaml +++ b/config/crd/bases/tenet.cybozu.io_networkpolicyadmissionrules.yaml @@ -16,7 +16,7 @@ spec: singular: networkpolicyadmissionrule scope: Cluster versions: - - name: v1beta1 + - name: v1beta2 schema: openAPIV3Schema: description: NetworkPolicyAdmissionRule is the Schema for the networkpolicyadmissionrules diff --git a/config/crd/bases/tenet.cybozu.io_networkpolicytemplates.yaml b/config/crd/bases/tenet.cybozu.io_networkpolicytemplates.yaml index ed2021c..31b5292 100644 --- a/config/crd/bases/tenet.cybozu.io_networkpolicytemplates.yaml +++ b/config/crd/bases/tenet.cybozu.io_networkpolicytemplates.yaml @@ -16,7 +16,7 @@ spec: singular: networkpolicytemplate scope: Cluster versions: - - name: v1beta1 + - name: v1beta2 schema: openAPIV3Schema: description: NetworkPolicyTemplate is the Schema for the networkpolicytemplates @@ -37,6 +37,11 @@ spec: spec: description: Spec is the spec for the NetworkPolicyTemplate properties: + clusterwide: + default: false + description: ClusterWide indicates whether the generated templates + are clusterwide templates + type: boolean policyTemplate: description: PolicyTemplate is a template for creating NetworkPolicies type: string diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index e7c8294..507a541 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -14,6 +14,17 @@ rules: - get - list - watch +- apiGroups: + - cilium.io + resources: + - ciliumclusterwidenetworkpolicies + verbs: + - create + - delete + - get + - list + - update + - watch - apiGroups: - cilium.io resources: diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index 11d7da5..a8f8880 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -33,14 +33,14 @@ webhooks: service: name: webhook-service namespace: system - path: /validate-tenet-cybozu-io-v1beta1-networkpolicyadmissionrule + path: /validate-tenet-cybozu-io-v1beta2-networkpolicyadmissionrule failurePolicy: Fail name: vnetworkpolicyadmissionrule.kb.io rules: - apiGroups: - tenet.cybozu.io apiVersions: - - v1beta1 + - v1beta2 operations: - CREATE - UPDATE diff --git a/controllers/networkpolicytemplate_controller.go b/controllers/networkpolicytemplate_controller.go index 2ae1864..d629b91 100644 --- a/controllers/networkpolicytemplate_controller.go +++ b/controllers/networkpolicytemplate_controller.go @@ -40,7 +40,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" "github.com/cybozu-go/tenet/pkg/cilium" "github.com/cybozu-go/tenet/pkg/tenet" ) @@ -61,6 +61,7 @@ type NetworkPolicyTemplateReconciler struct { //+kubebuilder:rbac:groups=tenet.cybozu.io,resources=networkpolicytemplates/finalizers,verbs=update //+kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch //+kubebuilder:rbac:groups="cilium.io",resources=ciliumnetworkpolicies,verbs=get;list;watch;create;update;delete +//+kubebuilder:rbac:groups="cilium.io",resources=ciliumclusterwidenetworkpolicies,verbs=get;list;watch;create;update;delete // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -70,7 +71,7 @@ type NetworkPolicyTemplateReconciler struct { func (r *NetworkPolicyTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) - npt := &tenetv1beta1.NetworkPolicyTemplate{} + npt := &tenetv1beta2.NetworkPolicyTemplate{} if err := r.Get(ctx, req.NamespacedName, npt); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -94,46 +95,51 @@ func (r *NetworkPolicyTemplateReconciler) Reconcile(ctx context.Context, req ctr return r.reconcileTemplate(ctx, npt) } -func (r *NetworkPolicyTemplateReconciler) shouldDelete(npt *tenetv1beta1.NetworkPolicyTemplate, ownerRefs []v1.OwnerReference) bool { +func (r *NetworkPolicyTemplateReconciler) shouldDelete(npt *tenetv1beta2.NetworkPolicyTemplate, ownerRefs []v1.OwnerReference) bool { for _, ownerRef := range ownerRefs { - if ownerRef.APIVersion == tenetv1beta1.GroupVersion.String() && ownerRef.Kind == tenetv1beta1.NetworkPolicyTemplateKind && ownerRef.Name == npt.Name { + if ownerRef.APIVersion == tenetv1beta2.GroupVersion.String() && ownerRef.Kind == tenetv1beta2.NetworkPolicyTemplateKind && ownerRef.Name == npt.Name { return true } } return false } -func (r *NetworkPolicyTemplateReconciler) finalize(ctx context.Context, npt *tenetv1beta1.NetworkPolicyTemplate) error { +func (r *NetworkPolicyTemplateReconciler) finalize(ctx context.Context, npt *tenetv1beta2.NetworkPolicyTemplate) error { if !controllerutil.ContainsFinalizer(npt, finalizerName) { return nil } logger := log.FromContext(ctx) - cnpl := cilium.CiliumNetworkPolicyList() - if err := r.List(ctx, cnpl); client.IgnoreNotFound(err) != nil { + var npl *unstructured.UnstructuredList + if npt.Spec.ClusterWide { + npl = cilium.CiliumClusterwideNetworkPolicyList() + } else { + npl = cilium.CiliumNetworkPolicyList() + } + if err := r.List(ctx, npl); client.IgnoreNotFound(err) != nil { return err } - for _, cnp := range cnpl.Items { - if cnp.GetDeletionTimestamp() != nil { + for _, np := range npl.Items { + if np.GetDeletionTimestamp() != nil { continue } - if !r.shouldDelete(npt, cnp.GetOwnerReferences()) { + if !r.shouldDelete(npt, np.GetOwnerReferences()) { continue } - if err := r.Delete(ctx, &cnp); err != nil { - return fmt.Errorf("failed to delete CiliumNetworkPolicy %s: %w", cnp.GetName(), err) + if err := r.Delete(ctx, &np); err != nil { + return fmt.Errorf("failed to delete %s %s: %w", np.GetKind(), np.GetName(), err) } - logger.Info("deleted CiliumNetworkPolicy", "name", cnp.GetName()) + logger.Info("deleted NetworkPolicy", "name", np.GetName(), "kind", np.GetKind()) } controllerutil.RemoveFinalizer(npt, finalizerName) return r.Update(ctx, npt) } -func (r *NetworkPolicyTemplateReconciler) reconcileTemplate(ctx context.Context, npt *tenetv1beta1.NetworkPolicyTemplate) (ctrl.Result, error) { +func (r *NetworkPolicyTemplateReconciler) reconcileTemplate(ctx context.Context, npt *tenetv1beta2.NetworkPolicyTemplate) (ctrl.Result, error) { logger := log.FromContext(ctx) - npt.Status = tenetv1beta1.NetworkPolicyTemplateOK + npt.Status = tenetv1beta2.NetworkPolicyTemplateOK nsl := &corev1.NamespaceList{} if err := r.List(ctx, nsl); err != nil { @@ -153,14 +159,24 @@ func (r *NetworkPolicyTemplateReconciler) reconcileTemplate(ctx context.Context, return ctrl.Result{}, nil } -func (r *NetworkPolicyTemplateReconciler) reconcileNetworkPolicy(ctx context.Context, npt *tenetv1beta1.NetworkPolicyTemplate, ns corev1.Namespace) error { +func (r *NetworkPolicyTemplateReconciler) reconcileNetworkPolicy(ctx context.Context, npt *tenetv1beta2.NetworkPolicyTemplate, ns corev1.Namespace) error { logger := log.FromContext(ctx) - existingNetworkPolicy := cilium.CiliumNetworkPolicy() - existingNetworkPolicyObjectKey := client.ObjectKey{ - Namespace: ns.Name, - Name: npt.Name, + var existingNetworkPolicy *unstructured.Unstructured + var existingNetworkPolicyObjectKey types.NamespacedName + if npt.Spec.ClusterWide { + existingNetworkPolicy = cilium.CiliumClusterwideNetworkPolicy() + existingNetworkPolicyObjectKey = client.ObjectKey{ + Name: fmt.Sprintf("%s-%s", ns.Name, npt.Name), + } + } else { + existingNetworkPolicy = cilium.CiliumNetworkPolicy() + existingNetworkPolicyObjectKey = client.ObjectKey{ + Namespace: ns.Name, + Name: npt.Name, + } } + existingNetworkPolicyError := r.Get(ctx, existingNetworkPolicyObjectKey, existingNetworkPolicy) if client.IgnoreNotFound(existingNetworkPolicyError) != nil { return existingNetworkPolicyError @@ -176,23 +192,23 @@ func (r *NetworkPolicyTemplateReconciler) reconcileNetworkPolicy(ctx context.Con currentNetworkPolicy, err := r.compileTemplate(npt, ns) if err != nil { - npt.Status = tenetv1beta1.NetworkPolicyTemplateInvalid + npt.Status = tenetv1beta2.NetworkPolicyTemplateInvalid logger.Error(err, "invalid template", "name", npt.Name) return err } if apierrors.IsNotFound(existingNetworkPolicyError) { - logger.Info("creating CiliumNetworkPolicy", "name", currentNetworkPolicy.GetName()) + logger.Info("creating NetworkPolicy", "name", currentNetworkPolicy.GetName(), "kind", currentNetworkPolicy.GetKind()) return r.Create(ctx, currentNetworkPolicy) } if equality.Semantic.DeepEqual(existingNetworkPolicy.UnstructuredContent()["spec"], currentNetworkPolicy.UnstructuredContent()["spec"]) { return nil } existingNetworkPolicy.UnstructuredContent()["spec"] = currentNetworkPolicy.DeepCopy().UnstructuredContent()["spec"] - logger.Info("updating CiliumNetworkPolicy", "name", existingNetworkPolicy.GetName()) + logger.Info("updating NetworkPolicy", "name", existingNetworkPolicy.GetName(), "kind", currentNetworkPolicy.GetKind()) return r.Update(ctx, existingNetworkPolicy) } -func (r *NetworkPolicyTemplateReconciler) isOptedIntoTemplate(npt *tenetv1beta1.NetworkPolicyTemplate, ns corev1.Namespace) bool { +func (r *NetworkPolicyTemplateReconciler) isOptedIntoTemplate(npt *tenetv1beta2.NetworkPolicyTemplate, ns corev1.Namespace) bool { for _, a := range strings.Split(ns.Annotations[tenet.PolicyAnnotation], ",") { if a == npt.Name { return true @@ -201,9 +217,15 @@ func (r *NetworkPolicyTemplateReconciler) isOptedIntoTemplate(npt *tenetv1beta1. return false } -func (r *NetworkPolicyTemplateReconciler) compileTemplate(npt *tenetv1beta1.NetworkPolicyTemplate, ns corev1.Namespace) (*unstructured.Unstructured, error) { - cnp := cilium.CiliumNetworkPolicy() - refCNP := cilium.CiliumNetworkPolicy() +func (r *NetworkPolicyTemplateReconciler) compileTemplate(npt *tenetv1beta2.NetworkPolicyTemplate, ns corev1.Namespace) (*unstructured.Unstructured, error) { + var np, refNP *unstructured.Unstructured + if npt.Spec.ClusterWide { + np = cilium.CiliumClusterwideNetworkPolicy() + refNP = cilium.CiliumClusterwideNetworkPolicy() + } else { + np = cilium.CiliumNetworkPolicy() + refNP = cilium.CiliumNetworkPolicy() + } tpl, err := template.New(npt.Name).Parse(npt.Spec.PolicyTemplate) if err != nil { return nil, err @@ -213,33 +235,36 @@ func (r *NetworkPolicyTemplateReconciler) compileTemplate(npt *tenetv1beta1.Netw return nil, err } y := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(buf.Bytes()), buf.Len()) - if err := y.Decode(cnp); err != nil { + if err := y.Decode(np); err != nil { return nil, err } - if cnp.GetAPIVersion() != refCNP.GetAPIVersion() || cnp.GetKind() != refCNP.GetKind() { - return nil, fmt.Errorf("invalid schema: %v", cnp.GetObjectKind().GroupVersionKind()) + if np.GetAPIVersion() != refNP.GetAPIVersion() || np.GetKind() != refNP.GetKind() { + return nil, fmt.Errorf("invalid schema: %v", np.GetObjectKind().GroupVersionKind()) } - cnp.SetNamespace(ns.Name) - cnp.SetName(npt.Name) - if err := controllerutil.SetOwnerReference(npt, cnp, r.Scheme); err != nil { + if npt.Spec.ClusterWide { + np.SetName(fmt.Sprintf("%s-%s", ns.Name, npt.Name)) + } else { + np.SetNamespace(ns.Name) + np.SetName(npt.Name) + } + if err := controllerutil.SetOwnerReference(npt, np, r.Scheme); err != nil { return nil, err } - return cnp, nil + return np, nil } // SetupWithManager sets up the controller with the Manager. func (r *NetworkPolicyTemplateReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager) error { logger := log.FromContext(ctx) - getOwner := func(o client.Object) []string { - cnp := cilium.CiliumNetworkPolicy() - if err := mgr.GetClient().Get(ctx, client.ObjectKeyFromObject(o), cnp); err != nil { + getOwner := func(o client.Object, t *unstructured.Unstructured) []string { + if err := mgr.GetClient().Get(ctx, client.ObjectKeyFromObject(o), t); err != nil { logger.Error(err, "failed to get CiliumNetworkPolicy") return nil } - owners := cnp.GetOwnerReferences() + owners := t.GetOwnerReferences() for _, owner := range owners { - if owner.APIVersion == tenetv1beta1.GroupVersion.String() && owner.Kind == tenetv1beta1.NetworkPolicyTemplateKind { + if owner.APIVersion == tenetv1beta2.GroupVersion.String() && owner.Kind == tenetv1beta2.NetworkPolicyTemplateKind { return []string{owner.Name} } } @@ -247,7 +272,7 @@ func (r *NetworkPolicyTemplateReconciler) SetupWithManager(ctx context.Context, } listNPTs := func(_ client.Object) []reconcile.Request { ctx := context.Background() - var nptl tenetv1beta1.NetworkPolicyTemplateList + var nptl tenetv1beta2.NetworkPolicyTemplateList if err := r.List(ctx, &nptl); err != nil { r.Log.Error(err, "failed to list NetworkPolicyTemplates") return nil @@ -263,15 +288,23 @@ func (r *NetworkPolicyTemplateReconciler) SetupWithManager(ctx context.Context, } filterCNP := func(o client.Object) []reconcile.Request { - if getOwner(o) == nil { + if getOwner(o, cilium.CiliumNetworkPolicy()) == nil { + return nil + } + return listNPTs(o) + } + + filterCCNP := func(o client.Object) []reconcile.Request { + if getOwner(o, cilium.CiliumClusterwideNetworkPolicy()) == nil { return nil } return listNPTs(o) } return ctrl.NewControllerManagedBy(mgr). - For(&tenetv1beta1.NetworkPolicyTemplate{}). + For(&tenetv1beta2.NetworkPolicyTemplate{}). Watches(&source.Kind{Type: &corev1.Namespace{}}, handler.EnqueueRequestsFromMapFunc(listNPTs)). Watches(&source.Kind{Type: cilium.CiliumNetworkPolicy()}, handler.EnqueueRequestsFromMapFunc(filterCNP)). + Watches(&source.Kind{Type: cilium.CiliumClusterwideNetworkPolicy()}, handler.EnqueueRequestsFromMapFunc(filterCCNP)). Complete(r) } diff --git a/controllers/networkpolicytemplate_controller_test.go b/controllers/networkpolicytemplate_controller_test.go index d805a87..26a664b 100644 --- a/controllers/networkpolicytemplate_controller_test.go +++ b/controllers/networkpolicytemplate_controller_test.go @@ -6,7 +6,7 @@ import ( "strings" "time" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" "github.com/cybozu-go/tenet/pkg/cilium" cacheclient "github.com/cybozu-go/tenet/pkg/client" "github.com/cybozu-go/tenet/pkg/tenet" @@ -32,6 +32,18 @@ spec: - toEndpoints: - matchLabels: "k8s:io.kubernetes.pod.namespace": {{.Name}} +` + intraNSCCNPTemplate = ` +apiVersion: cilium.io/v2 +kind: CiliumClusterwideNetworkPolicy +spec: + endpointSelector: + matchLabels: + k8s:io.kubernetes.pod.namespace: {{.Name}} + ingress: + - fromEndpoints: + - matchLabels: + "k8s.io.cilium.k8s.namespace.labels.team": {{ index .Labels "team" }} ` expectedCNPTemplate = ` apiVersion: cilium.io/v2 @@ -65,12 +77,12 @@ spec: ` ) -func newDummyNetworkPolicyTemplate(o client.ObjectKey, tmpl string) *tenetv1beta1.NetworkPolicyTemplate { - return &tenetv1beta1.NetworkPolicyTemplate{ +func newDummyNetworkPolicyTemplate(o client.ObjectKey, tmpl string) *tenetv1beta2.NetworkPolicyTemplate { + return &tenetv1beta2.NetworkPolicyTemplate{ ObjectMeta: v1.ObjectMeta{ Name: o.Name, }, - Spec: tenetv1beta1.NetworkPolicyTemplateSpec{ + Spec: tenetv1beta2.NetworkPolicyTemplateSpec{ PolicyTemplate: tmpl, }, } @@ -154,15 +166,15 @@ var _ = Describe("Tenet controller", func() { Expect(err).NotTo(HaveOccurred()) Expect(equality.Semantic.DeepEqual(cnp.UnstructuredContent()["spec"], expectedCNP.UnstructuredContent()["spec"])).To(BeTrue()) - Eventually(func() tenetv1beta1.NetworkPolicyTemplateStatus { - npt := &tenetv1beta1.NetworkPolicyTemplate{} + Eventually(func() tenetv1beta2.NetworkPolicyTemplateStatus { + npt := &tenetv1beta2.NetworkPolicyTemplate{} nptKey := client.ObjectKey{ Name: nptName, } err := k8sClient.Get(ctx, nptKey, npt) Expect(err).NotTo(HaveOccurred()) return npt.Status - }).Should(Equal(tenetv1beta1.NetworkPolicyTemplateOK)) + }).Should(Equal(tenetv1beta2.NetworkPolicyTemplateOK)) }) It("should leave opted-out namespaces alone", func() { @@ -181,6 +193,33 @@ var _ = Describe("Tenet controller", func() { }).ShouldNot(Succeed()) }) + It("should create CiliumClusterwideNetworkPolicy", func() { + nptName := uuid.NewString()[:16] + nsName := uuid.NewString()[:16] + + npt := newDummyNetworkPolicyTemplate(client.ObjectKey{Name: nptName}, intraNSCCNPTemplate) + npt.Spec.ClusterWide = true + err := k8sClient.Create(ctx, npt) + Expect(err).NotTo(HaveOccurred()) + + ns := &corev1.Namespace{} + ns.Name = nsName + + ns.SetAnnotations(map[string]string{tenet.PolicyAnnotation: nptName}) + ns.SetLabels(map[string]string{"team": "my-team"}) + + err = k8sClient.Create(ctx, ns) + Expect(err).NotTo(HaveOccurred()) + + Eventually(func() error { + ccnp := cilium.CiliumClusterwideNetworkPolicy() + key := client.ObjectKey{ + Name: fmt.Sprintf("%s-%s", nsName, nptName), + } + return k8sClient.Get(ctx, key, ccnp) + }).Should(Succeed()) + }) + It("should apply all opted-in templates", func() { nsName := uuid.NewString() nptName1 := uuid.NewString() @@ -222,7 +261,7 @@ var _ = Describe("Tenet controller", func() { return k8sClient.Get(ctx, key, cnp) }).Should(Succeed()) - npt := &tenetv1beta1.NetworkPolicyTemplate{} + npt := &tenetv1beta2.NetworkPolicyTemplate{} nptKey := client.ObjectKey{ Name: nptName, } @@ -326,7 +365,7 @@ var _ = Describe("Tenet controller", func() { shouldCreateNetworkPolicyTemplate(ctx, nptName, intraNSTemplate) shouldCreateNamespace(ctx, nsName, []string{nptName}) - npt := &tenetv1beta1.NetworkPolicyTemplate{} + npt := &tenetv1beta2.NetworkPolicyTemplate{} nptKey := client.ObjectKey{ Name: nptName, } @@ -364,7 +403,7 @@ var _ = Describe("Tenet controller", func() { shouldCreateNetworkPolicyTemplate(ctx, bmcNptName, bmcDenyTemplate) shouldCreateNamespace(ctx, nsName, []string{intraNSNptName, bmcNptName}) - npt := &tenetv1beta1.NetworkPolicyTemplate{} + npt := &tenetv1beta2.NetworkPolicyTemplate{} nptKey := client.ObjectKey{ Name: intraNSNptName, } @@ -413,15 +452,15 @@ var _ = Describe("Tenet controller", func() { shouldCreateNetworkPolicyTemplate(ctx, nptName, invalidTemplate) shouldCreateNamespace(ctx, nsName, []string{nptName}) - Eventually(func() tenetv1beta1.NetworkPolicyTemplateStatus { - npt := &tenetv1beta1.NetworkPolicyTemplate{} + Eventually(func() tenetv1beta2.NetworkPolicyTemplateStatus { + npt := &tenetv1beta2.NetworkPolicyTemplate{} nptKey := client.ObjectKey{ Name: nptName, } err := k8sClient.Get(ctx, nptKey, npt) Expect(err).NotTo(HaveOccurred()) return npt.Status - }).Should(Equal(tenetv1beta1.NetworkPolicyTemplateInvalid)) + }).Should(Equal(tenetv1beta2.NetworkPolicyTemplateInvalid)) Consistently(func() error { cnp := cilium.CiliumNetworkPolicy() diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 79538c9..c7e9a8d 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -33,7 +33,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" //+kubebuilder:scaffold:imports ) @@ -78,7 +78,7 @@ var _ = BeforeSuite(func() { scheme = runtime.NewScheme() err = clientgoscheme.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) - err = tenetv1beta1.AddToScheme(scheme) + err = tenetv1beta2.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) //+kubebuilder:scaffold:scheme diff --git a/docs/clusterwidenetworkpolicytemplate.md b/docs/clusterwidenetworkpolicytemplate.md new file mode 100644 index 0000000..365a4db --- /dev/null +++ b/docs/clusterwidenetworkpolicytemplate.md @@ -0,0 +1,56 @@ +# ClusterwideNetworkPolicyTemplate +`ClusterwideNetworkPolicyTemplate` works similarly to `NetworkPolicyTemplate` but serves to write `CiliumClusterwideNetworkPolicy` templates that tenants can opt-into via the `tenet.cybozu.io/network-policy-template` annotation in their `Namespace` resources. Unlike CiliumNetworkPolicies created from a `NetworkPolicyTemplate`, CiliumClusterwideNetworkPolicies created from `ClusterwideNetworkPolicyTemplate` are cluster-wide resources. + +```yaml +# clusterwide-network-policy-template.yaml +apiVersion: tenet.cybozu.io/v1beta1 +kind: ClusterwideNetworkPolicyTemplate +metadata: + name: allow-team-ingress +spec: + policyTemplate: | + apiVersion: cilium.io/v2 + kind: CiliumClusterwideNetworkPolicy + metadata: + name: {{.Name}}-allow-team-ingress + spec: + endpointSelector: + matchLabels: + k8s:io.kubernetes.pod.namespace: {{.Name}} + ingress: + - fromEndpoints: + - matchLabels: + "k8s:io.cilium.k8s.namespace.labels.team": {{ index .Labels "team" }} +``` + +When a tenant namespace is annotated like below, + +```yaml +# namespace.yaml +apiVersion: v1 +kind: Namespace +metadata: + name: my-namespace + annotations: + tenet.cybozu.io/network-policy-template: allow-team-ingress + labels: + accurate.cybozu.com/type: root + team: my-team +``` + +The following `CiliumClusterwideNetworkPolicy` will be created with cluster scope: + +```yaml +apiVersion: cilium.io/v2 +kind: CiliumClusterwideNetworkPolicy +metadata: + name: my-namespace-allow-team-ingress +spec: + endpointSelector: + matchLabels: + k8s:io.kubernetes.pod.namespace: my-namespace + ingress: + - fromEndpoints: + - matchLabels: + "k8s:io.cilium.k8s.namespace.labels.team": my-team +``` diff --git a/docs/networkpolicytemplate.md b/docs/networkpolicytemplate.md index 5228696..0b67614 100644 --- a/docs/networkpolicytemplate.md +++ b/docs/networkpolicytemplate.md @@ -1,5 +1,5 @@ # NetworkPolicyTemplate -`NetworkPolicyTemplate` enables administrators to write `CiliumNetworkPolicy` templates that tenants can opt-into via the `tenet.cybozu.io/network-policy-template` annotation in their `Namespace` resources. Templates can be supplied with values sources from the `.metadata` field of the `Namespace` resource that reference them. When annotations are placed on a root namespace managed by Accurate the annotations, and thus the templated CiliumNetworkPolicies, can be propagated to child namespaces. For instance, given the following `NetworkPolicyTemplate`, +`NetworkPolicyTemplate` enables administrators to write `CiliumNetworkPolicy` or `CiliumClusterwideNetworkPolicy` templates that tenants can opt-into via the `tenet.cybozu.io/network-policy-template` annotation in their `Namespace` resources. Templates can be supplied with values sources from the `.metadata` field of the `Namespace` resource that reference them. When annotations are placed on a root namespace managed by Accurate the annotations, and thus the templated CiliumNetworkPolicies, can be propagated to child namespaces. For instance, given the following `NetworkPolicyTemplate`, ```yaml # network-policy-template.yaml @@ -52,3 +52,5 @@ spec: ``` If `my-namespace` is an Accurate root namespace, any of its child namespace will inherit the `tenet.cybozu.io/network-policy-template` annotation and CiliumNetworkPolicies will be created with the templates filled-in. + +To write `CiliumClusterwideNetworkPolicy` templates, set `.spec.clusterwide: true` on `NetworkPolicyTemplate`. diff --git a/docs/overview.md b/docs/overview.md index 92bfd46..b227b20 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -8,7 +8,7 @@ To enhance the security without sacrificing convenience, we want to provide defa ## Features - Allow cluster administrators to provide network policy templates tenants can opt into - - currently only `CiliumNetworkPolicy` templates are supported + - currently `CiliumNetworkPolicy` and `CiliumClusterwideNetworkPolicy` templates are supported - Automatically generate network policies on namespaces that opt into them - when used in conjunction with `Accurate`, resource generation is also performed on SubNamespaces - Allow cluster administrators to place restrictions on the expressivity of network policies diff --git a/e2e/Makefile b/e2e/Makefile index c9eb596..6455cbd 100644 --- a/e2e/Makefile +++ b/e2e/Makefile @@ -27,6 +27,7 @@ start: $(KIND) $(KUBECTL) $(HELM) $(KUBECTL) apply -f https://github.com/jetstack/cert-manager/releases/download/v$(CERT_MANAGER_VERSION)/cert-manager.yaml $(KUBECTL) -n cert-manager wait --for=condition=available --timeout=180s --all deployments $(KUBECTL) apply -f https://github.com/cilium/cilium/raw/$(CILIUM_VERSION)/pkg/k8s/apis/cilium.io/client/crds/v2/ciliumnetworkpolicies.yaml + $(KUBECTL) apply -f https://github.com/cilium/cilium/raw/$(CILIUM_VERSION)/pkg/k8s/apis/cilium.io/client/crds/v2/ciliumclusterwidenetworkpolicies.yaml $(HELM) install --create-namespace --namespace $(PROJECT_NAME) $(PROJECT_NAME) ../charts/$(PROJECT_NAME) -f values.yaml $(KUBECTL) -n $(PROJECT_NAME) wait --for=condition=available --timeout=180s --all deployments $(KUBECTL) -n kube-system wait --for=condition=available --timeout=180s --all deployments diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index a714297..5dd1aa3 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -17,6 +17,7 @@ import ( const ( allowIntraNSEgressPolicyName = "allow-intra-namespace-egress" + clusterwideNPTName = "clusterwide-npt" bmcDenyPolicyName = "bmc-deny" dummyPolicyName = "dummy" ) @@ -99,6 +100,20 @@ var _ = Describe("NetworkPolicyTemplate", func() { }).Should(Succeed()) }) + It("should create CiliumClusterwideNetworkPolicy", func() { + By("setting up namespace") + nsName := uuid.NewString() + kubectlSafe(nil, "create", "ns", nsName) + kubectlSafe(nil, "label", "ns", nsName, "team=my-team") + kubectlSafe(nil, "annotate", "ns", nsName, fmt.Sprintf("%s=%s", tenet.PolicyAnnotation, clusterwideNPTName)) + + By("checking propagation") + Consistently(func() error { + _, err := kubectl(nil, "get", "CiliumClusterwideNetworkPolicy", fmt.Sprintf("%s-clusterwide-npt", nsName)) + return err + }).Should(Succeed()) + }) + It("should prevent deletion of managed CiliumNetworkPolicies", func() { By("setting up namespace") nsName := uuid.NewString() diff --git a/e2e/suite_test.go b/e2e/suite_test.go index 5baf2b1..85b3e5a 100644 --- a/e2e/suite_test.go +++ b/e2e/suite_test.go @@ -16,6 +16,9 @@ var ( //go:embed t/bmc-deny-npt.yaml bmcDenyNetworkPolicyTemplate []byte + //go:embed t/clusterwide-npt.yaml + clusterwideNetworkPolicyTemplate []byte + //go:embed t/bmc-deny-npar.yaml bmcDenyNetworkPolicyAdmissionRule []byte ) @@ -36,6 +39,7 @@ var _ = BeforeSuite(func() { By("setting up default NetworkPolicyTemplates") kubectlSafe(intraNSNetworkPolicyTemplate, "apply", "-f", "-") kubectlSafe(bmcDenyNetworkPolicyTemplate, "apply", "-f", "-") + kubectlSafe(clusterwideNetworkPolicyTemplate, "apply", "-f", "-") By("setting up default NetworkPolicyAdmissionRules") kubectlSafe(bmcDenyNetworkPolicyAdmissionRule, "apply", "-f", "-") diff --git a/e2e/t/bmc-deny-npar.yaml b/e2e/t/bmc-deny-npar.yaml index e697959..30b0d09 100644 --- a/e2e/t/bmc-deny-npar.yaml +++ b/e2e/t/bmc-deny-npar.yaml @@ -1,4 +1,4 @@ -apiVersion: tenet.cybozu.io/v1beta1 +apiVersion: tenet.cybozu.io/v1beta2 kind: NetworkPolicyAdmissionRule metadata: name: bmc-deny diff --git a/e2e/t/bmc-deny-npt.yaml b/e2e/t/bmc-deny-npt.yaml index 69b5a7b..d889a54 100644 --- a/e2e/t/bmc-deny-npt.yaml +++ b/e2e/t/bmc-deny-npt.yaml @@ -1,4 +1,4 @@ -apiVersion: tenet.cybozu.io/v1beta1 +apiVersion: tenet.cybozu.io/v1beta2 kind: NetworkPolicyTemplate metadata: name: bmc-deny diff --git a/e2e/t/clusterwide-npt.yaml b/e2e/t/clusterwide-npt.yaml new file mode 100644 index 0000000..c99dc84 --- /dev/null +++ b/e2e/t/clusterwide-npt.yaml @@ -0,0 +1,17 @@ +apiVersion: tenet.cybozu.io/v1beta2 +kind: NetworkPolicyTemplate +metadata: + name: clusterwide-npt +spec: + clusterwide: true + policyTemplate: | + apiVersion: cilium.io/v2 + kind: CiliumClusterwideNetworkPolicy + spec: + endpointSelector: + matchLabels: + k8s:io.kubernetes.pod.namespace: {{.Name}} + ingress: + - fromEndpoints: + - matchLabels: + "k8s.io.cilium.k8s.namespace.labels.team": {{ index .Labels "team" }} diff --git a/e2e/t/dummy-npt.yaml b/e2e/t/dummy-npt.yaml index 0e20cb6..4c625ce 100644 --- a/e2e/t/dummy-npt.yaml +++ b/e2e/t/dummy-npt.yaml @@ -1,4 +1,4 @@ -apiVersion: tenet.cybozu.io/v1beta1 +apiVersion: tenet.cybozu.io/v1beta2 kind: NetworkPolicyTemplate metadata: name: dummy diff --git a/e2e/t/intra-namespace-npt.yaml b/e2e/t/intra-namespace-npt.yaml index d884fd3..ce6aac0 100644 --- a/e2e/t/intra-namespace-npt.yaml +++ b/e2e/t/intra-namespace-npt.yaml @@ -1,4 +1,4 @@ -apiVersion: tenet.cybozu.io/v1beta1 +apiVersion: tenet.cybozu.io/v1beta2 kind: NetworkPolicyTemplate metadata: name: allow-intra-namespace-egress diff --git a/hooks/ciliumnetworkpolicy.go b/hooks/ciliumnetworkpolicy.go index c8d6bab..d87133c 100644 --- a/hooks/ciliumnetworkpolicy.go +++ b/hooks/ciliumnetworkpolicy.go @@ -14,7 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" "github.com/cybozu-go/tenet/pkg/cilium" ) @@ -49,7 +49,7 @@ func (v *ciliumNetworkPolicyValidator) handleDelete(_ context.Context, req admis } owners := cnp.GetOwnerReferences() for _, owner := range owners { - if owner.APIVersion == tenetv1beta1.GroupVersion.String() && owner.Kind == tenetv1beta1.NetworkPolicyTemplateKind { + if owner.APIVersion == tenetv1beta2.GroupVersion.String() && owner.Kind == tenetv1beta2.NetworkPolicyTemplateKind { if req.UserInfo.Username == v.serviceAccountName { return admission.Allowed("deletion by service account") } @@ -68,7 +68,7 @@ func (v *ciliumNetworkPolicyValidator) handleCreateOrUpdate(ctx context.Context, if err := v.Get(ctx, client.ObjectKey{Name: cnp.GetNamespace()}, ns); client.IgnoreNotFound(err) != nil { return admission.Errored(http.StatusInternalServerError, err) } - var nparl tenetv1beta1.NetworkPolicyAdmissionRuleList + var nparl tenetv1beta2.NetworkPolicyAdmissionRuleList if err := v.List(ctx, &nparl); err != nil { return admission.Errored(http.StatusInternalServerError, err) } @@ -217,7 +217,7 @@ func (v *ciliumNetworkPolicyValidator) gatherPoliciesFromCIDRSetRule(rule interf return policies, nil } -func (v *ciliumNetworkPolicyValidator) gatherFilters(nparl *tenetv1beta1.NetworkPolicyAdmissionRuleList) ([]*net.IPNet, []*net.IPNet, error) { +func (v *ciliumNetworkPolicyValidator) gatherFilters(nparl *tenetv1beta2.NetworkPolicyAdmissionRuleList) ([]*net.IPNet, []*net.IPNet, error) { var egressFilters, ingressFilters []*net.IPNet for _, npar := range nparl.Items { for _, ipRange := range npar.Spec.ForbiddenIPRanges { @@ -226,12 +226,12 @@ func (v *ciliumNetworkPolicyValidator) gatherFilters(nparl *tenetv1beta1.Network return nil, nil, err } switch ipRange.Type { - case tenetv1beta1.NetworkPolicyAdmissionRuleTypeAll: + case tenetv1beta2.NetworkPolicyAdmissionRuleTypeAll: egressFilters = append(egressFilters, cidr) ingressFilters = append(ingressFilters, cidr) - case tenetv1beta1.NetworkPolicyAdmissionRuleTypeEgress: + case tenetv1beta2.NetworkPolicyAdmissionRuleTypeEgress: egressFilters = append(egressFilters, cidr) - case tenetv1beta1.NetworkPolicyAdmissionRuleTypeIngress: + case tenetv1beta2.NetworkPolicyAdmissionRuleTypeIngress: ingressFilters = append(ingressFilters, cidr) } } @@ -261,7 +261,7 @@ func (v *ciliumNetworkPolicyValidator) validate(egressPolicies, ingressPolicies, return admission.Allowed("") } -func (v *ciliumNetworkPolicyValidator) shouldValidate(ns *corev1.Namespace, nparl *tenetv1beta1.NetworkPolicyAdmissionRuleList) bool { +func (v *ciliumNetworkPolicyValidator) shouldValidate(ns *corev1.Namespace, nparl *tenetv1beta2.NetworkPolicyAdmissionRuleList) bool { for _, npar := range nparl.Items { for k, v := range npar.Spec.NamespaceSelector.ExcludeLabels { if ns.Labels[k] == v { diff --git a/hooks/ciliumnetworkpolicy_test.go b/hooks/ciliumnetworkpolicy_test.go index 89128de..c2bb0ab 100644 --- a/hooks/ciliumnetworkpolicy_test.go +++ b/hooks/ciliumnetworkpolicy_test.go @@ -14,7 +14,7 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" "sigs.k8s.io/controller-runtime/pkg/client" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" "github.com/cybozu-go/tenet/pkg/cilium" ) @@ -48,17 +48,17 @@ var _ = Describe("CiliumNetworkPolicy webhook", func() { ctx := context.Background() BeforeEach(func() { - npar := &tenetv1beta1.NetworkPolicyAdmissionRule{ + npar := &tenetv1beta2.NetworkPolicyAdmissionRule{ ObjectMeta: v1.ObjectMeta{ Name: "default-rule", }, - Spec: tenetv1beta1.NetworkPolicyAdmissionRuleSpec{ - NamespaceSelector: tenetv1beta1.NetworkPolicyAdmissionRuleNamespaceSelector{ + Spec: tenetv1beta2.NetworkPolicyAdmissionRuleSpec{ + NamespaceSelector: tenetv1beta2.NetworkPolicyAdmissionRuleNamespaceSelector{ ExcludeLabels: map[string]string{ "team": "neco", }, }, - ForbiddenIPRanges: []tenetv1beta1.NetworkPolicyAdmissionRuleForbiddenIPRanges{ + ForbiddenIPRanges: []tenetv1beta2.NetworkPolicyAdmissionRuleForbiddenIPRanges{ { CIDR: "10.72.16.0/20", Type: "egress", @@ -77,7 +77,7 @@ var _ = Describe("CiliumNetworkPolicy webhook", func() { err := k8sClient.Create(ctx, npar) Expect(err).NotTo(HaveOccurred()) Eventually(func() error { - npar := &tenetv1beta1.NetworkPolicyAdmissionRule{} + npar := &tenetv1beta2.NetworkPolicyAdmissionRule{} key := client.ObjectKey{ Name: "default-rule", } @@ -86,7 +86,7 @@ var _ = Describe("CiliumNetworkPolicy webhook", func() { }) AfterEach(func() { - err := k8sClient.DeleteAllOf(ctx, &tenetv1beta1.NetworkPolicyAdmissionRule{}) + err := k8sClient.DeleteAllOf(ctx, &tenetv1beta2.NetworkPolicyAdmissionRule{}) Expect(err).NotTo(HaveOccurred()) }) @@ -182,7 +182,7 @@ var _ = Describe("CiliumNetworkPolicy webhook", func() { cnp.SetNamespace(nsName) cnp.SetOwnerReferences([]v1.OwnerReference{ { - APIVersion: tenetv1beta1.GroupVersion.String(), + APIVersion: tenetv1beta2.GroupVersion.String(), Kind: "NetworkPolicyTemplate", Name: "dummy", UID: types.UID(uuid.NewString()), diff --git a/hooks/networkpolicyadmissionrule.go b/hooks/networkpolicyadmissionrule.go index c6fc4ea..5805968 100644 --- a/hooks/networkpolicyadmissionrule.go +++ b/hooks/networkpolicyadmissionrule.go @@ -10,10 +10,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" ) -//+kubebuilder:webhook:path=/validate-tenet-cybozu-io-v1beta1-networkpolicyadmissionrule,mutating=false,failurePolicy=fail,sideEffects=None,groups=tenet.cybozu.io,resources=networkpolicyadmissionrules,verbs=create;update,versions=v1beta1,name=vnetworkpolicyadmissionrule.kb.io,admissionReviewVersions={v1} +//+kubebuilder:webhook:path=/validate-tenet-cybozu-io-v1beta2-networkpolicyadmissionrule,mutating=false,failurePolicy=fail,sideEffects=None,groups=tenet.cybozu.io,resources=networkpolicyadmissionrules,verbs=create;update,versions=v1beta2,name=vnetworkpolicyadmissionrule.kb.io,admissionReviewVersions={v1} type networkPolicyAdmissionRuleValidator struct { client.Client @@ -24,7 +24,7 @@ var _ admission.Handler = &networkPolicyAdmissionRuleValidator{} // Handle validates the NetworkPolicyAdmissionRule. func (v *networkPolicyAdmissionRuleValidator) Handle(ctx context.Context, req admission.Request) admission.Response { - npar := &tenetv1beta1.NetworkPolicyAdmissionRule{} + npar := &tenetv1beta2.NetworkPolicyAdmissionRule{} if err := v.dec.Decode(req, npar); err != nil { return admission.Errored(http.StatusBadRequest, err) } @@ -45,5 +45,5 @@ func SetupNetworkPolicyAdmissionRuleWebhook(mgr manager.Manager, dec *admission. dec: dec, } srv := mgr.GetWebhookServer() - srv.Register("/validate-tenet-cybozu-io-v1beta1-networkpolicyadmissionrule", &webhook.Admission{Handler: v}) + srv.Register("/validate-tenet-cybozu-io-v1beta2-networkpolicyadmissionrule", &webhook.Admission{Handler: v}) } diff --git a/hooks/networkpolicyadmissionrule_test.go b/hooks/networkpolicyadmissionrule_test.go index 3ef5749..af8f871 100644 --- a/hooks/networkpolicyadmissionrule_test.go +++ b/hooks/networkpolicyadmissionrule_test.go @@ -8,19 +8,19 @@ import ( . "github.com/onsi/gomega" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" ) var _ = Describe("NetworkPolicyAdmissionRule webhook", func() { ctx := context.Background() It("should deny the creation of a NetworkPolicyAdmissionRule with malformed CIDR", func() { - npar := &tenetv1beta1.NetworkPolicyAdmissionRule{ + npar := &tenetv1beta2.NetworkPolicyAdmissionRule{ ObjectMeta: v1.ObjectMeta{ Name: uuid.NewString(), }, - Spec: tenetv1beta1.NetworkPolicyAdmissionRuleSpec{ - ForbiddenIPRanges: []tenetv1beta1.NetworkPolicyAdmissionRuleForbiddenIPRanges{ + Spec: tenetv1beta2.NetworkPolicyAdmissionRuleSpec{ + ForbiddenIPRanges: []tenetv1beta2.NetworkPolicyAdmissionRuleForbiddenIPRanges{ { CIDR: "300.300.300.0/12", Type: "all", @@ -33,13 +33,13 @@ var _ = Describe("NetworkPolicyAdmissionRule webhook", func() { }) It("should deny the creation of a NetworkPolicyAdmissionRule without connection type", func() { - npar := &tenetv1beta1.NetworkPolicyAdmissionRule{ + npar := &tenetv1beta2.NetworkPolicyAdmissionRule{ ObjectMeta: v1.ObjectMeta{ Name: uuid.NewString(), Namespace: "default", }, - Spec: tenetv1beta1.NetworkPolicyAdmissionRuleSpec{ - ForbiddenIPRanges: []tenetv1beta1.NetworkPolicyAdmissionRuleForbiddenIPRanges{ + Spec: tenetv1beta2.NetworkPolicyAdmissionRuleSpec{ + ForbiddenIPRanges: []tenetv1beta2.NetworkPolicyAdmissionRuleForbiddenIPRanges{ { CIDR: "10.0.0.0/24", }, @@ -51,13 +51,13 @@ var _ = Describe("NetworkPolicyAdmissionRule webhook", func() { }) It("should allow valid NetworkPolicyAdmissionRules", func() { - npar := &tenetv1beta1.NetworkPolicyAdmissionRule{ + npar := &tenetv1beta2.NetworkPolicyAdmissionRule{ ObjectMeta: v1.ObjectMeta{ Name: uuid.NewString(), Namespace: "default", }, - Spec: tenetv1beta1.NetworkPolicyAdmissionRuleSpec{ - ForbiddenIPRanges: []tenetv1beta1.NetworkPolicyAdmissionRuleForbiddenIPRanges{ + Spec: tenetv1beta2.NetworkPolicyAdmissionRuleSpec{ + ForbiddenIPRanges: []tenetv1beta2.NetworkPolicyAdmissionRuleForbiddenIPRanges{ { CIDR: "10.0.0.0/24", Type: "egress", diff --git a/hooks/suite_test.go b/hooks/suite_test.go index dc0ab00..1d655ff 100644 --- a/hooks/suite_test.go +++ b/hooks/suite_test.go @@ -22,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - tenetv1beta1 "github.com/cybozu-go/tenet/api/v1beta1" + tenetv1beta2 "github.com/cybozu-go/tenet/api/v1beta2" //+kubebuilder:scaffold:imports ) @@ -64,7 +64,7 @@ var _ = BeforeSuite(func() { scheme := runtime.NewScheme() err = clientgoscheme.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) - err = tenetv1beta1.AddToScheme(scheme) + err = tenetv1beta2.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) err = admissionv1beta1.AddToScheme(scheme) diff --git a/pkg/cilium/ciliumclusterwidenetworkpolicy.go b/pkg/cilium/ciliumclusterwidenetworkpolicy.go new file mode 100644 index 0000000..d9ada2f --- /dev/null +++ b/pkg/cilium/ciliumclusterwidenetworkpolicy.go @@ -0,0 +1,27 @@ +package cilium + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +//revive:disable:exported +func CiliumClusterwideNetworkPolicy() *unstructured.Unstructured { + ccnp := &unstructured.Unstructured{} + ccnp.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "cilium.io", + Version: CiliumNetworkPolicyVersion, + Kind: "CiliumClusterwideNetworkPolicy", + }) + return ccnp +} + +func CiliumClusterwideNetworkPolicyList() *unstructured.UnstructuredList { + ccnpl := &unstructured.UnstructuredList{} + ccnpl.SetGroupVersionKind(schema.GroupVersionKind{ + Group: "cilium.io", + Version: CiliumNetworkPolicyVersion, + Kind: "CiliumClusterwideNetworkPolicyList", + }) + return ccnpl +}