diff --git a/PROJECT b/PROJECT index 7a2355d..ac81e7e 100644 --- a/PROJECT +++ b/PROJECT @@ -32,7 +32,7 @@ resources: controller: true domain: engen.priv.no group: unifi - kind: FirewallRule + kind: FirewallPolicy path: github.com/vegardengen/unifi-network-operator/api/v1beta1 version: v1beta1 version: "3" diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 0a8eca9..475626d 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -3,7 +3,6 @@ package v1beta1 // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. -// FirewallRuleSpec defines the desired state of FirewallRule. type NamedUnifiResource struct { Name string `json:"name,omitempty"` ID string `json:"id,omitempty"` @@ -22,7 +21,7 @@ type FirewallZoneEntry struct { Namespace string `json:"namespace,omitempty"` Name string `json:"name,omitempty"` } -type FirewallRuleEntry struct { +type FirewallPolicyEntry struct { Namespace string `json:"namespace,omitempty"` Name string `json:"name,omitempty"` } diff --git a/api/v1beta1/firewallgroup_types.go b/api/v1beta1/firewallgroup_types.go index db1dec5..1312916 100644 --- a/api/v1beta1/firewallgroup_types.go +++ b/api/v1beta1/firewallgroup_types.go @@ -41,7 +41,7 @@ type FirewallGroupSpec struct { ManualPorts []string `json:"manualPorts,omitempty"` ManualServices []ServiceEntry `json:"manual_services,omitempty"` - AutoCreatedFrom FirewallRuleEntry `json:"auto_created_from,omitempty"` + AutoCreatedFrom FirewallPolicyEntry `json:"auto_created_from,omitempty"` // AutoIncludeSelector defines which services to extract addresses from // +optional diff --git a/api/v1beta1/firewallrule_types.go b/api/v1beta1/firewallpolicy_types.go similarity index 70% rename from api/v1beta1/firewallrule_types.go rename to api/v1beta1/firewallpolicy_types.go index 54ab304..855de5b 100644 --- a/api/v1beta1/firewallrule_types.go +++ b/api/v1beta1/firewallpolicy_types.go @@ -23,7 +23,7 @@ import ( // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. -// FirewallRuleSpec defines the desired state of FirewallRule. +// FirewallPolicySpec defines the desired state of FirewallPolicy. // type ServiceSpec struct { // Namespace string `json:"namespace,omitempty"` // Name string `json:"name,omitempty"` @@ -39,7 +39,7 @@ import ( // Services []ServiceSpec `json:"service,omitempty"` //} -type FirewallRuleSpec struct { +type FirewallPolicySpec struct { Name string `json:"name"` Source FirewallSource `json:"source"` Destination FirewallDestination `json:"destination"` @@ -47,17 +47,17 @@ type FirewallRuleSpec struct { MatchServicesInAllNamespaces bool `json:"match_services_in_all_namespaces,omitempty"` } -// FirewallRuleStatus defines the observed state of FirewallRule. -type FirewallRuleStatus struct { - ResourcesManaged *FirewallRuleResourcesManaged `json:"resources_managed,omitempty"` +// FirewallPolicyStatus defines the observed state of FirewallPolicy. +type FirewallPolicyStatus struct { + ResourcesManaged *FirewallPolicyResourcesManaged `json:"resources_managed,omitempty"` } -type FirewallRuleResourcesManaged struct { - UnifiFirewallRules []UnifiFirewallRuleEntry `json:"firewall_rules_managed,omitempty"` - FirewallGroups []FirewallGroupEntry `json:"firewall_groups_managed,omitempty"` +type FirewallPolicyResourcesManaged struct { + UnifiFirewallPolicies []UnifiFirewallPolicyEntry `json:"firewall_policies_managed,omitempty"` + FirewallGroups []FirewallGroupEntry `json:"firewall_groups_managed,omitempty"` } -type UnifiFirewallRuleEntry struct { +type UnifiFirewallPolicyEntry struct { From string `json:"from"` To string `json:"to"` TcpIpv4ID string `json:"tcpipv4_id"` @@ -69,24 +69,24 @@ type UnifiFirewallRuleEntry struct { // +kubebuilder:object:root=true // +kubebuilder:subresource:status -// FirewallRule is the Schema for the firewallrules API. -type FirewallRule struct { +// FirewallPolicy is the Schema for the firewallpolicies API. +type FirewallPolicy struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec FirewallRuleSpec `json:"spec,omitempty"` - Status FirewallRuleStatus `json:"status,omitempty"` + Spec FirewallPolicySpec `json:"spec,omitempty"` + Status FirewallPolicyStatus `json:"status,omitempty"` } // +kubebuilder:object:root=true -// FirewallRuleList contains a list of FirewallRule. -type FirewallRuleList struct { +// FirewallPolicyList contains a list of FirewallPolicy. +type FirewallPolicyList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []FirewallRule `json:"items"` + Items []FirewallPolicy `json:"items"` } func init() { - SchemeBuilder.Register(&FirewallRule{}, &FirewallRuleList{}) + SchemeBuilder.Register(&FirewallPolicy{}, &FirewallPolicyList{}) } diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 2c5bb7f..365e9b6 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -240,7 +240,7 @@ func (in *FirewallGroupStatus) DeepCopy() *FirewallGroupStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FirewallRule) DeepCopyInto(out *FirewallRule) { +func (in *FirewallPolicy) DeepCopyInto(out *FirewallPolicy) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -248,18 +248,18 @@ func (in *FirewallRule) DeepCopyInto(out *FirewallRule) { in.Status.DeepCopyInto(&out.Status) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRule. -func (in *FirewallRule) DeepCopy() *FirewallRule { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallPolicy. +func (in *FirewallPolicy) DeepCopy() *FirewallPolicy { if in == nil { return nil } - out := new(FirewallRule) + out := new(FirewallPolicy) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FirewallRule) DeepCopyObject() runtime.Object { +func (in *FirewallPolicy) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -267,46 +267,46 @@ func (in *FirewallRule) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FirewallRuleEntry) DeepCopyInto(out *FirewallRuleEntry) { +func (in *FirewallPolicyEntry) DeepCopyInto(out *FirewallPolicyEntry) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleEntry. -func (in *FirewallRuleEntry) DeepCopy() *FirewallRuleEntry { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallPolicyEntry. +func (in *FirewallPolicyEntry) DeepCopy() *FirewallPolicyEntry { if in == nil { return nil } - out := new(FirewallRuleEntry) + out := new(FirewallPolicyEntry) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FirewallRuleList) DeepCopyInto(out *FirewallRuleList) { +func (in *FirewallPolicyList) DeepCopyInto(out *FirewallPolicyList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]FirewallRule, len(*in)) + *out = make([]FirewallPolicy, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleList. -func (in *FirewallRuleList) DeepCopy() *FirewallRuleList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallPolicyList. +func (in *FirewallPolicyList) DeepCopy() *FirewallPolicyList { if in == nil { return nil } - out := new(FirewallRuleList) + out := new(FirewallPolicyList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FirewallRuleList) DeepCopyObject() runtime.Object { +func (in *FirewallPolicyList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -314,11 +314,11 @@ func (in *FirewallRuleList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FirewallRuleResourcesManaged) DeepCopyInto(out *FirewallRuleResourcesManaged) { +func (in *FirewallPolicyResourcesManaged) DeepCopyInto(out *FirewallPolicyResourcesManaged) { *out = *in - if in.UnifiFirewallRules != nil { - in, out := &in.UnifiFirewallRules, &out.UnifiFirewallRules - *out = make([]UnifiFirewallRuleEntry, len(*in)) + if in.UnifiFirewallPolicies != nil { + in, out := &in.UnifiFirewallPolicies, &out.UnifiFirewallPolicies + *out = make([]UnifiFirewallPolicyEntry, len(*in)) copy(*out, *in) } if in.FirewallGroups != nil { @@ -328,49 +328,49 @@ func (in *FirewallRuleResourcesManaged) DeepCopyInto(out *FirewallRuleResourcesM } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleResourcesManaged. -func (in *FirewallRuleResourcesManaged) DeepCopy() *FirewallRuleResourcesManaged { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallPolicyResourcesManaged. +func (in *FirewallPolicyResourcesManaged) DeepCopy() *FirewallPolicyResourcesManaged { if in == nil { return nil } - out := new(FirewallRuleResourcesManaged) + out := new(FirewallPolicyResourcesManaged) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FirewallRuleSpec) DeepCopyInto(out *FirewallRuleSpec) { +func (in *FirewallPolicySpec) DeepCopyInto(out *FirewallPolicySpec) { *out = *in in.Source.DeepCopyInto(&out.Source) in.Destination.DeepCopyInto(&out.Destination) } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleSpec. -func (in *FirewallRuleSpec) DeepCopy() *FirewallRuleSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallPolicySpec. +func (in *FirewallPolicySpec) DeepCopy() *FirewallPolicySpec { if in == nil { return nil } - out := new(FirewallRuleSpec) + out := new(FirewallPolicySpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FirewallRuleStatus) DeepCopyInto(out *FirewallRuleStatus) { +func (in *FirewallPolicyStatus) DeepCopyInto(out *FirewallPolicyStatus) { *out = *in if in.ResourcesManaged != nil { in, out := &in.ResourcesManaged, &out.ResourcesManaged - *out = new(FirewallRuleResourcesManaged) + *out = new(FirewallPolicyResourcesManaged) (*in).DeepCopyInto(*out) } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleStatus. -func (in *FirewallRuleStatus) DeepCopy() *FirewallRuleStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallPolicyStatus. +func (in *FirewallPolicyStatus) DeepCopy() *FirewallPolicyStatus { if in == nil { return nil } - out := new(FirewallRuleStatus) + out := new(FirewallPolicyStatus) in.DeepCopyInto(out) return out } @@ -698,16 +698,16 @@ func (in *ServiceEntry) DeepCopy() *ServiceEntry { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UnifiFirewallRuleEntry) DeepCopyInto(out *UnifiFirewallRuleEntry) { +func (in *UnifiFirewallPolicyEntry) DeepCopyInto(out *UnifiFirewallPolicyEntry) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UnifiFirewallRuleEntry. -func (in *UnifiFirewallRuleEntry) DeepCopy() *UnifiFirewallRuleEntry { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UnifiFirewallPolicyEntry. +func (in *UnifiFirewallPolicyEntry) DeepCopy() *UnifiFirewallPolicyEntry { if in == nil { return nil } - out := new(UnifiFirewallRuleEntry) + out := new(UnifiFirewallPolicyEntry) in.DeepCopyInto(out) return out } diff --git a/cmd/main.go b/cmd/main.go index 23ce8e1..2775ea7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -233,13 +233,13 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "FirewallZone") os.Exit(1) } - if err = (&controller.FirewallRuleReconciler{ + if err = (&controller.FirewallPolicyReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), UnifiClient: unifiClient, ConfigLoader: configLoader, }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "FirewallRule") + setupLog.Error(err, "unable to create controller", "controller", "FirewallPolicy") os.Exit(1) } // +kubebuilder:scaffold:builder diff --git a/config/crd/bases/unifi.engen.priv.no_firewallgroups.yaml b/config/crd/bases/unifi.engen.priv.no_firewallgroups.yaml index 415a0b8..6814433 100644 --- a/config/crd/bases/unifi.engen.priv.no_firewallgroups.yaml +++ b/config/crd/bases/unifi.engen.priv.no_firewallgroups.yaml @@ -147,7 +147,6 @@ spec: resources_managed: properties: ipv4_object: - description: FirewallRuleSpec defines the desired state of FirewallRule. properties: id: type: string @@ -155,7 +154,6 @@ spec: type: string type: object ipv6_object: - description: FirewallRuleSpec defines the desired state of FirewallRule. properties: id: type: string @@ -163,7 +161,6 @@ spec: type: string type: object tcp_ports_object: - description: FirewallRuleSpec defines the desired state of FirewallRule. properties: id: type: string @@ -171,7 +168,6 @@ spec: type: string type: object udp_ports_object: - description: FirewallRuleSpec defines the desired state of FirewallRule. properties: id: type: string diff --git a/config/crd/bases/unifi.engen.priv.no_firewallrules.yaml b/config/crd/bases/unifi.engen.priv.no_firewallpolicies.yaml similarity index 91% rename from config/crd/bases/unifi.engen.priv.no_firewallrules.yaml rename to config/crd/bases/unifi.engen.priv.no_firewallpolicies.yaml index b6d8c1b..a67997d 100644 --- a/config/crd/bases/unifi.engen.priv.no_firewallrules.yaml +++ b/config/crd/bases/unifi.engen.priv.no_firewallpolicies.yaml @@ -4,20 +4,20 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.17.2 - name: firewallrules.unifi.engen.priv.no + name: firewallpolicies.unifi.engen.priv.no spec: group: unifi.engen.priv.no names: - kind: FirewallRule - listKind: FirewallRuleList - plural: firewallrules - singular: firewallrule + kind: FirewallPolicy + listKind: FirewallPolicyList + plural: firewallpolicies + singular: firewallpolicy scope: Namespaced versions: - name: v1beta1 schema: openAPIV3Schema: - description: FirewallRule is the Schema for the firewallrules API. + description: FirewallPolicy is the Schema for the firewallpolicies API. properties: apiVersion: description: |- @@ -92,7 +92,7 @@ spec: - source type: object status: - description: FirewallRuleStatus defines the observed state of FirewallRule. + description: FirewallPolicyStatus defines the observed state of FirewallPolicy. properties: resources_managed: properties: @@ -105,7 +105,7 @@ spec: type: string type: object type: array - firewall_rules_managed: + firewall_policies_managed: items: properties: from: diff --git a/config/crd/bases/unifi.engen.priv.no_firewallzones.yaml b/config/crd/bases/unifi.engen.priv.no_firewallzones.yaml index 22b296d..09d9910 100644 --- a/config/crd/bases/unifi.engen.priv.no_firewallzones.yaml +++ b/config/crd/bases/unifi.engen.priv.no_firewallzones.yaml @@ -59,7 +59,6 @@ spec: properties: firewall_zones_managed: items: - description: FirewallRuleSpec defines the desired state of FirewallRule. properties: id: type: string diff --git a/config/crd/bases/unifi.engen.priv.no_networkconfigurations.yaml b/config/crd/bases/unifi.engen.priv.no_networkconfigurations.yaml index cc0f436..6a1c939 100644 --- a/config/crd/bases/unifi.engen.priv.no_networkconfigurations.yaml +++ b/config/crd/bases/unifi.engen.priv.no_networkconfigurations.yaml @@ -97,7 +97,6 @@ spec: properties: networks_managed: items: - description: FirewallRuleSpec defines the desired state of FirewallRule. properties: id: type: string diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 7fa1ee1..43d8cae 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -4,7 +4,7 @@ resources: - bases/unifi.engen.priv.no_networkconfigurations.yaml - bases/unifi.engen.priv.no_firewallzones.yaml -- bases/unifi.engen.priv.no_firewallrules.yaml +- bases/unifi.engen.priv.no_firewallpolicies.yaml # +kubebuilder:scaffold:crdkustomizeresource patches: diff --git a/config/rbac/firewallrule_admin_role.yaml b/config/rbac/firewallpolicy_admin_role.yaml similarity index 89% rename from config/rbac/firewallrule_admin_role.yaml rename to config/rbac/firewallpolicy_admin_role.yaml index 42478e7..8b160a3 100644 --- a/config/rbac/firewallrule_admin_role.yaml +++ b/config/rbac/firewallpolicy_admin_role.yaml @@ -11,17 +11,17 @@ metadata: labels: app.kubernetes.io/name: unifi-network-operator app.kubernetes.io/managed-by: kustomize - name: firewallrule-admin-role + name: firewallpolicy-admin-role rules: - apiGroups: - unifi.engen.priv.no resources: - - firewallrules + - firewallpolicies verbs: - '*' - apiGroups: - unifi.engen.priv.no resources: - - firewallrules/status + - firewallpolicies/status verbs: - get diff --git a/config/rbac/firewallrule_editor_role.yaml b/config/rbac/firewallpolicy_editor_role.yaml similarity index 90% rename from config/rbac/firewallrule_editor_role.yaml rename to config/rbac/firewallpolicy_editor_role.yaml index 68e9a14..3a22a72 100644 --- a/config/rbac/firewallrule_editor_role.yaml +++ b/config/rbac/firewallpolicy_editor_role.yaml @@ -11,12 +11,12 @@ metadata: labels: app.kubernetes.io/name: unifi-network-operator app.kubernetes.io/managed-by: kustomize - name: firewallrule-editor-role + name: firewallpolicy-editor-role rules: - apiGroups: - unifi.engen.priv.no resources: - - firewallrules + - firewallpolicies verbs: - create - delete @@ -28,6 +28,6 @@ rules: - apiGroups: - unifi.engen.priv.no resources: - - firewallrules/status + - firewallpolicies/status verbs: - get diff --git a/config/rbac/firewallrule_viewer_role.yaml b/config/rbac/firewallpolicy_viewer_role.yaml similarity index 89% rename from config/rbac/firewallrule_viewer_role.yaml rename to config/rbac/firewallpolicy_viewer_role.yaml index 5a74d67..a70d52f 100644 --- a/config/rbac/firewallrule_viewer_role.yaml +++ b/config/rbac/firewallpolicy_viewer_role.yaml @@ -11,12 +11,12 @@ metadata: labels: app.kubernetes.io/name: unifi-network-operator app.kubernetes.io/managed-by: kustomize - name: firewallrule-viewer-role + name: firewallpolicy-viewer-role rules: - apiGroups: - unifi.engen.priv.no resources: - - firewallrules + - firewallpolicies verbs: - get - list @@ -24,6 +24,6 @@ rules: - apiGroups: - unifi.engen.priv.no resources: - - firewallrules/status + - firewallpolicies/status verbs: - get diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml index 82abcd5..35cb3ce 100644 --- a/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -22,9 +22,9 @@ resources: # default, aiding admins in cluster management. Those roles are # not used by the {{ .ProjectName }} itself. You can comment the following lines # if you do not want those helpers be installed with your Project. -- firewallrule_admin_role.yaml -- firewallrule_editor_role.yaml -- firewallrule_viewer_role.yaml +- firewallpolicy_admin_role.yaml +- firewallpolicy_editor_role.yaml +- firewallpolicy_viewer_role.yaml - firewallzone_admin_role.yaml - firewallzone_editor_role.yaml - firewallzone_viewer_role.yaml diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 3db7b1c..36ebe8c 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -17,7 +17,7 @@ rules: - unifi.engen.priv.no resources: - firewallgroups - - firewallrules + - firewallpolicies - firewallzones - networkconfigurations verbs: @@ -32,7 +32,7 @@ rules: - unifi.engen.priv.no resources: - firewallgroups/finalizers - - firewallrules/finalizers + - firewallpolicies/finalizers - firewallzones/finalizers - networkconfigurations/finalizers verbs: @@ -41,7 +41,7 @@ rules: - unifi.engen.priv.no resources: - firewallgroups/status - - firewallrules/status + - firewallpolicies/status - firewallzones/status - networkconfigurations/status verbs: diff --git a/config/samples/unifi_v1beta1_firewallrule.yaml b/config/samples/unifi_v1beta1_firewallpolicy.yaml similarity index 75% rename from config/samples/unifi_v1beta1_firewallrule.yaml rename to config/samples/unifi_v1beta1_firewallpolicy.yaml index b1c287c..117b2c0 100644 --- a/config/samples/unifi_v1beta1_firewallrule.yaml +++ b/config/samples/unifi_v1beta1_firewallpolicy.yaml @@ -1,8 +1,8 @@ apiVersion: unifi.engen.priv.no/v1beta1 -kind: FirewallRule +kind: FirewallPolicy metadata: labels: app.kubernetes.io/name: unifi-network-operator app.kubernetes.io/managed-by: kustomize - name: firewallrule-sample + name: firewallpolicy-sample spec: diff --git a/internal/controller/firewallpolicy_controller.go b/internal/controller/firewallpolicy_controller.go new file mode 100644 index 0000000..6d37323 --- /dev/null +++ b/internal/controller/firewallpolicy_controller.go @@ -0,0 +1,826 @@ +/* +Copyright 2025 Vegard Engen. + +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 controller + +import ( + "context" + "fmt" + // "strings" + "encoding/json" + "strings" + "time" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/log" + + goUnifi "github.com/vegardengen/go-unifi/unifi" + unifiv1beta1 "github.com/vegardengen/unifi-network-operator/api/v1beta1" + "github.com/vegardengen/unifi-network-operator/internal/config" + "github.com/vegardengen/unifi-network-operator/internal/unifi" +) + +// FirewallPolicyReconciler reconciles a FirewallPolicy object +type FirewallPolicyReconciler struct { + client.Client + Scheme *runtime.Scheme + UnifiClient *unifi.UnifiClient + ConfigLoader *config.ConfigLoaderType +} + +const firewallPolicyFinalizer = "finalizer.unifi.engen.priv.no/firewallpolicy" + +// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallpolicies,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallpolicies/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallpolicies/finalizers,verbs=update +// +kubebuilder:rbac:groups="",resources=configmaps,verbs=list;get;watch +// +kubebuilder:rbac:groups="",resources=services,verbs=list;get;watch + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the FirewallPolicy object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.2/pkg/reconcile + +func fillDefaultPolicy() goUnifi.FirewallPolicy { + var firewallPolicy goUnifi.FirewallPolicy + firewallPolicy.Action = "ALLOW" + firewallPolicy.CreateAllowRespond = true + firewallPolicy.ConnectionStateType = "ALL" + firewallPolicy.ConnectionStates = []string{} + firewallPolicy.Destination = goUnifi.FirewallDestination{ + MatchOppositePorts: false, + MatchingTarget: "IP", + MatchingTargetType: "OBJECT", + } + firewallPolicy.Enabled = true + firewallPolicy.ICMPTypename = "ANY" + firewallPolicy.ICMPV6Typename = "ANY" + firewallPolicy.MatchIPSec = false + firewallPolicy.MatchOppositeProtocol = false + firewallPolicy.Predefined = false + firewallPolicy.Schedule = goUnifi.FirewallSchedule{ + Mode: "ALWAYS", + RepeatOnDays: []string{}, + TimeAllDay: false, + } + firewallPolicy.Source = goUnifi.FirewallSource{ + MatchMac: false, + MatchOppositePorts: false, + MatchOppositeNetworks: false, + } + + return firewallPolicy +} + +func (r *FirewallPolicyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := log.FromContext(ctx) + + // TODO(user): your logic here + + cfg, err := r.ConfigLoader.GetConfig(ctx, "unifi-operator-config") + if err != nil { + return ctrl.Result{}, err + } + + defaultNs := cfg.Data["defaultNamespace"] + kubernetesZone := cfg.Data["kubernetesUnifiZone"] + var kubernetesZoneID string + log.Info(defaultNs) + log.Info(kubernetesZone) + + var firewallPolicy unifiv1beta1.FirewallPolicy + + if err := r.Get(ctx, req.NamespacedName, &firewallPolicy); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + log.Info(firewallPolicy.Spec.Name) + + if firewallPolicy.DeletionTimestamp != nil { + if controllerutil.ContainsFinalizer(&firewallPolicy, firewallPolicyFinalizer) { + err := r.UnifiClient.Reauthenticate() + if err != nil { + return ctrl.Result{}, err + } + log.Info("Running finalizer logic for FirewallPolicy", "name", firewallPolicy.Name) + + if len(firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies) > 0 { + for i, UnifiFirewallPolicy := range firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies { + log.Info(fmt.Sprintf("From: %s to: %s TcpIpv4: %s UdpIpv4: %s TcpIpv6: %s UdpIpv6: %s", UnifiFirewallPolicy.From, UnifiFirewallPolicy.To, UnifiFirewallPolicy.TcpIpv4ID, UnifiFirewallPolicy.UdpIpv4ID, UnifiFirewallPolicy.TcpIpv6ID, UnifiFirewallPolicy.UdpIpv6ID)) + if len(UnifiFirewallPolicy.TcpIpv4ID) > 0 { + err := r.UnifiClient.Client.DeleteFirewallPolicy(context.Background(), r.UnifiClient.SiteID, UnifiFirewallPolicy.TcpIpv4ID) + if err != nil && !strings.Contains(err.Error(), "not found") { + } else { + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[i].TcpIpv4ID = "" + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + } + } + if len(UnifiFirewallPolicy.UdpIpv4ID) > 0 { + err := r.UnifiClient.Client.DeleteFirewallPolicy(context.Background(), r.UnifiClient.SiteID, UnifiFirewallPolicy.UdpIpv4ID) + if err != nil && !strings.Contains(err.Error(), "not found") { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } else { + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[i].UdpIpv4ID = "" + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + } + } + if len(UnifiFirewallPolicy.TcpIpv6ID) > 0 { + err := r.UnifiClient.Client.DeleteFirewallPolicy(context.Background(), r.UnifiClient.SiteID, UnifiFirewallPolicy.TcpIpv6ID) + if err != nil && !strings.Contains(err.Error(), "not found") { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } else { + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[i].TcpIpv6ID = "" + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + } + } + if len(UnifiFirewallPolicy.UdpIpv6ID) > 0 { + err := r.UnifiClient.Client.DeleteFirewallPolicy(context.Background(), r.UnifiClient.SiteID, UnifiFirewallPolicy.UdpIpv6ID) + if err != nil && !strings.Contains(err.Error(), "not found") { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } else { + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[i].UdpIpv6ID = "" + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + } + } + } + } + + if len(firewallPolicy.Status.ResourcesManaged.FirewallGroups) > 0 { + for i, firewallGroup := range firewallPolicy.Status.ResourcesManaged.FirewallGroups { + var firewallGroupCRD unifiv1beta1.FirewallGroup + if firewallGroup.Name != "" { + if err := r.Get(ctx, types.NamespacedName{Name: firewallGroup.Name, Namespace: firewallGroup.Namespace}, &firewallGroupCRD); err != nil { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + if err := r.Delete(ctx, &firewallGroupCRD); err != nil { + log.Error(err, "Could not delete firewall group") + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + firewallPolicy.Status.ResourcesManaged.FirewallGroups[i].Name = "" + firewallPolicy.Status.ResourcesManaged.FirewallGroups[i].Namespace = "" + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + } + } + } + controllerutil.RemoveFinalizer(&firewallPolicy, firewallPolicyFinalizer) + if err := r.Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + + log.Info("Successfully finalized FirewallGroup") + } + return ctrl.Result{}, nil + } + if !controllerutil.ContainsFinalizer(&firewallPolicy, firewallPolicyFinalizer) { + controllerutil.AddFinalizer(&firewallPolicy, firewallPolicyFinalizer) + if err := r.Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + } + + firewallpolicyindex := make(map[string]int) + + nextIndex := 0 + if firewallPolicy.Status.ResourcesManaged == nil { + firewallGroupsManaged := []unifiv1beta1.FirewallGroupEntry{} + unifiFirewallPolicies := []unifiv1beta1.UnifiFirewallPolicyEntry{} + firewallPolicy.Status.ResourcesManaged = &unifiv1beta1.FirewallPolicyResourcesManaged{ + UnifiFirewallPolicies: unifiFirewallPolicies, + FirewallGroups: firewallGroupsManaged, + } + } else { + for index, firewallPolicyEntry := range firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies { + firewallpolicyindex[firewallPolicyEntry.From+"/"+firewallPolicyEntry.To] = index + nextIndex = nextIndex + 1 + } + } + err = r.UnifiClient.Reauthenticate() + if err != nil { + return ctrl.Result{}, err + } + + var zoneCRDs unifiv1beta1.FirewallZoneList + var networkCRDs unifiv1beta1.NetworkconfigurationList + + err = r.List(ctx, &zoneCRDs) + if err != nil { + log.Error(err, "Could not list firewall zones") + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + + zoneCRDNames := make(map[string]int) + + for i, zoneCRD := range zoneCRDs.Items { + namespace := defaultNs + if len(zoneCRD.Namespace) > 0 { + namespace = zoneCRD.Namespace + } + if kubernetesZone == zoneCRD.Name { + kubernetesZoneID = zoneCRD.Spec.ID + log.Info(fmt.Sprintf("Zone for kubernetes resources: %s with ID %s", kubernetesZone, kubernetesZoneID)) + } + zoneCRDNames[namespace+"/"+zoneCRD.Name] = i + } + + err = r.List(ctx, &networkCRDs) + if err != nil { + log.Error(err, "Could not list networks") + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + + networkCRDNames := make(map[string]int) + + for i, networkCRD := range networkCRDs.Items { + namespace := defaultNs + if len(networkCRD.Namespace) > 0 { + namespace = networkCRD.Namespace + } + networkCRDNames[namespace+"/"+networkCRD.Name] = i + } + + destination_services := make(map[string]struct{}) + destination_groups := make(map[string]struct{}) + + for _, dest_group := range firewallPolicy.Spec.Destination.FirewallGroups { + namespace := defaultNs + if len(dest_group.Namespace) > 0 { + namespace = dest_group.Namespace + } + destination_groups[namespace+"/"+dest_group.Name] = struct{}{} + } + for _, dest_service := range firewallPolicy.Spec.Destination.Services { + namespace := defaultNs + if len(dest_service.Namespace) > 0 { + namespace = dest_service.Namespace + } + destination_services[namespace+"/"+dest_service.Name] = struct{}{} + } + log.Info(fmt.Sprintf("%+v", destination_services)) + var firewallGroupCRDs unifiv1beta1.FirewallGroupList + var myFirewallGroups []unifiv1beta1.FirewallGroup + if err = r.List(ctx, &firewallGroupCRDs); err != nil { + log.Error(err, "Failed to list firewall groups") + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + + for _, firewallGroup := range firewallGroupCRDs.Items { + if val, found := firewallGroup.Annotations["unifi.engen.priv.no/firewall-policy"]; found && val == firewallPolicy.Name { + myFirewallGroups = append(myFirewallGroups, firewallGroup) + } else if _, found := destination_groups[firewallGroup.Namespace+"/"+firewallGroup.Name]; found { + myFirewallGroups = append(myFirewallGroups, firewallGroup) + } + } + myFirewallGroupNames := make(map[string]struct{}) + for _, firewallGroup := range myFirewallGroups { + myFirewallGroupNames[firewallGroup.Name] = struct{}{} + } + var serviceCRDs corev1.ServiceList + var myServices []corev1.Service + if err = r.List(ctx, &serviceCRDs); err != nil { + log.Error(err, "Failed to list services") + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } + for _, service := range serviceCRDs.Items { + skipService := false + if val, found := service.Annotations["unifi.engen.priv.no/firewall-group"]; found { + if _, found := myFirewallGroupNames[val]; found { + skipService = true + } + } + if val, found := service.Annotations["unifi.engen.priv.no/firewall-policy"]; found && val == firewallPolicy.Name && !skipService { + myServices = append(myServices, service) + } else if _, found := destination_services[service.Namespace+"/"+service.Name]; found && !skipService { + myServices = append(myServices, service) + } + } + + for _, service := range myServices { + log.Info(fmt.Sprintf("Should handle service %s", service.Name)) + var firewallGroupCRD unifiv1beta1.FirewallGroup + if err := r.Get(ctx, types.NamespacedName{ + Name: toKubeName("k8s-auto" + "_" + service.Namespace + "/" + service.Name), + Namespace: firewallPolicy.Namespace, + }, &firewallGroupCRD); err == nil { + myFirewallGroups = append(myFirewallGroups, firewallGroupCRD) + } else { + log.Info("Going to create firewall group") + var manualServices []unifiv1beta1.ServiceEntry + manualServices = append(manualServices, unifiv1beta1.ServiceEntry{ + Name: service.Name, + Namespace: service.Namespace, + }) + createdFirewallGroupCRD := &unifiv1beta1.FirewallGroup{ + ObjectMeta: ctrl.ObjectMeta{ + Name: toKubeName("k8s-auto" + "_" + service.Namespace + "/" + service.Name), + Namespace: firewallPolicy.Namespace, + }, + Spec: unifiv1beta1.FirewallGroupSpec{ + Name: "auto-" + service.Namespace + "/" + service.Name, + AutoCreatedFrom: unifiv1beta1.FirewallPolicyEntry{ + Name: firewallPolicy.Name, + Namespace: firewallPolicy.Namespace, + }, + ManualServices: manualServices, + MatchServicesInAllNamespaces: true, + }, + } + log.Info(fmt.Sprintf("%+v", createdFirewallGroupCRD)) + if err := r.Create(ctx, createdFirewallGroupCRD); err != nil { + log.Error(err, fmt.Sprintf("Failed to create %s", createdFirewallGroupCRD.Name)) + return ctrl.Result{RequeueAfter: 10 * time.Minute}, err + } else { + time.Sleep(10 * time.Second) + _ = r.Get(ctx, types.NamespacedName{Name: createdFirewallGroupCRD.Name, Namespace: createdFirewallGroupCRD.Namespace}, &firewallGroupCRD) + } + log.Info(fmt.Sprintf("Adding %+v", firewallGroupCRD)) + myFirewallGroups = append(myFirewallGroups, firewallGroupCRD) + found := false + for _, managedFirewallGroup := range firewallPolicy.Status.ResourcesManaged.FirewallGroups { + if managedFirewallGroup.Name == firewallGroupCRD.Name && managedFirewallGroup.Namespace == firewallGroupCRD.Namespace { + found = true + } + } + if !found { + firewallPolicy.Status.ResourcesManaged.FirewallGroups = append(firewallPolicy.Status.ResourcesManaged.FirewallGroups, unifiv1beta1.FirewallGroupEntry{Name: firewallGroupCRD.Name, Namespace: firewallGroupCRD.Namespace}) + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + log.Error(err, "Failed to update status with added firewallgroup") + } + } + + } + } + unifi_firewall_policies, err := r.UnifiClient.Client.ListFirewallPolicy(context.Background(), r.UnifiClient.SiteID) + if err != nil { + log.Error(err, "Could not list firewall policies") + return ctrl.Result{}, err + } + unifiFirewallpolicyNames := make(map[string]struct{}) + for _, unifi_firewall_policy := range unifi_firewall_policies { + unifiFirewallpolicyNames[unifi_firewall_policy.Name] = struct{}{} + } + log.Info(fmt.Sprintf("Number of firewall policies: %d", len(unifi_firewall_policies))) + + for _, zoneEntry := range firewallPolicy.Spec.Source.FirewallZones { + namespace := defaultNs + if len(zoneEntry.Namespace) > 0 { + namespace = zoneEntry.Namespace + } + if i, found := zoneCRDNames[namespace+"/"+zoneEntry.Name]; found { + log.Info(fmt.Sprintf("Creating firewallpolicies for %s", zoneCRDs.Items[i].Name)) + for _, firewallGroup := range myFirewallGroups { + found := false + index, found := firewallpolicyindex["zone:"+zoneCRDs.Items[i].Name+"/"+firewallGroup.Name] + if !found { + firewallPolicyEntry := unifiv1beta1.UnifiFirewallPolicyEntry{ + From: "zone:" + zoneCRDs.Items[i].Name, + To: firewallGroup.Name, + TcpIpv4ID: "", + UdpIpv4ID: "", + TcpIpv6ID: "", + UdpIpv6ID: "", + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies = append(firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies, firewallPolicyEntry) + index = nextIndex + nextIndex = nextIndex + 1 + } + + if len(firewallGroup.Status.ResolvedIPV4Addresses) > 0 { + if len(firewallGroup.Status.ResolvedTCPPorts) > 0 { + policyname := "k8s-fw-" + firewallPolicy.Name + "-" + zoneCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv4-tcp" + if _, found := unifiFirewallpolicyNames[policyname]; !found { + log.Info(fmt.Sprintf("Creating ipv4 tcp firewallpolicy for %s to %s: %s", zoneCRDs.Items[i].Name, firewallGroup.Name, policyname)) + unifiFirewallPolicy := fillDefaultPolicy() + unifiFirewallPolicy.Name = policyname + unifiFirewallPolicy.Source.PortMatchingType = "ANY" + unifiFirewallPolicy.Source.ZoneID = zoneCRDs.Items[i].Spec.ID + unifiFirewallPolicy.Source.MatchingTarget = "ANY" + unifiFirewallPolicy.Protocol = "tcp" + unifiFirewallPolicy.IPVersion = "IPV4" + unifiFirewallPolicy.Description = fmt.Sprintf("Allow tcp IPV4 from %s to %s", zoneCRDs.Items[i].Name, firewallGroup.Name) + unifiFirewallPolicy.Destination.MatchingTargetType = "OBJECT" + unifiFirewallPolicy.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV4Object.ID + unifiFirewallPolicy.Destination.MatchingTarget = "IP" + unifiFirewallPolicy.Destination.PortMatchingType = "OBJECT" + unifiFirewallPolicy.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID + unifiFirewallPolicy.Destination.ZoneID = kubernetesZoneID + + log.Info(fmt.Sprintf("Trying to create firewall policy from zone %s to %s: %+v", zoneCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallPolicy)) + pretty, _ := json.MarshalIndent(unifiFirewallPolicy, "", " ") + log.Info(string(pretty)) + updatedPolicy, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallPolicy) + if err != nil { + log.Error(err, "Could not create firewall policy") + return ctrl.Result{}, err + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[index].TcpIpv4ID = updatedPolicy.ID + if err = r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + } else { + log.Info(fmt.Sprintf("Firewall policy for ipv4 tcp %s to %s already exists", zoneCRDs.Items[i].Name, firewallGroup.Name)) + } + } + if len(firewallGroup.Status.ResolvedUDPPorts) > 0 { + policyname := "k8s-fw-" + firewallPolicy.Name + "-" + zoneCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv4-udp" + if _, found := unifiFirewallpolicyNames[policyname]; !found { + log.Info(fmt.Sprintf("Creating ipv4 udp firewallpolicy for %s to %s: %s", zoneCRDs.Items[i].Name, firewallGroup.Name, policyname)) + unifiFirewallPolicy := fillDefaultPolicy() + unifiFirewallPolicy.Name = policyname + unifiFirewallPolicy.Source.PortMatchingType = "ANY" + unifiFirewallPolicy.Source.ZoneID = zoneCRDs.Items[i].Spec.ID + unifiFirewallPolicy.Source.MatchingTarget = "ANY" + unifiFirewallPolicy.Protocol = "udp" + unifiFirewallPolicy.IPVersion = "IPV4" + unifiFirewallPolicy.Description = fmt.Sprintf("Allow udp IPV4 from %s to %s", zoneCRDs.Items[i].Name, firewallGroup.Name) + unifiFirewallPolicy.Destination.MatchingTargetType = "OBJECT" + unifiFirewallPolicy.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV4Object.ID + unifiFirewallPolicy.Destination.MatchingTarget = "IP" + unifiFirewallPolicy.Destination.PortMatchingType = "OBJECT" + unifiFirewallPolicy.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID + unifiFirewallPolicy.Destination.ZoneID = kubernetesZoneID + + log.Info(fmt.Sprintf("Trying to create firewall policy from zone %s to %s: %+v", zoneCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallPolicy)) + pretty, _ := json.MarshalIndent(unifiFirewallPolicy, "", " ") + log.Info(string(pretty)) + updatedPolicy, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallPolicy) + if err != nil { + log.Error(err, "Could not create firewall policy") + return ctrl.Result{}, err + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[index].UdpIpv4ID = updatedPolicy.ID + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + + } else { + log.Info(fmt.Sprintf("Firewall policy for ipv4 udp %s to %s already exists", zoneCRDs.Items[i].Name, firewallGroup.Name)) + } + } + } + if len(firewallGroup.Status.ResolvedIPV6Addresses) > 0 { + if len(firewallGroup.Status.ResolvedTCPPorts) > 0 { + policyname := "k8s-fw-" + firewallPolicy.Name + "-" + zoneCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv6-tcp" + if _, found := unifiFirewallpolicyNames[policyname]; !found { + log.Info(fmt.Sprintf("Creating ipv6 tcp firewallpolicy for %s to %s: %s", zoneCRDs.Items[i].Name, firewallGroup.Name, policyname)) + unifiFirewallPolicy := fillDefaultPolicy() + unifiFirewallPolicy.Name = policyname + unifiFirewallPolicy.Source.PortMatchingType = "ANY" + unifiFirewallPolicy.Source.ZoneID = zoneCRDs.Items[i].Spec.ID + unifiFirewallPolicy.Source.MatchingTarget = "ANY" + unifiFirewallPolicy.Protocol = "tcp" + unifiFirewallPolicy.IPVersion = "IPV6" + unifiFirewallPolicy.Description = fmt.Sprintf("Allow tcp IPV6 from %s to %s", zoneCRDs.Items[i].Name, firewallGroup.Name) + unifiFirewallPolicy.Destination.MatchingTargetType = "OBJECT" + unifiFirewallPolicy.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV6Object.ID + unifiFirewallPolicy.Destination.MatchingTarget = "IP" + unifiFirewallPolicy.Destination.PortMatchingType = "OBJECT" + unifiFirewallPolicy.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID + unifiFirewallPolicy.Destination.ZoneID = kubernetesZoneID + + log.Info(fmt.Sprintf("Trying to create firewall policy from zone %s to %s: %+v", zoneCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallPolicy)) + pretty, _ := json.MarshalIndent(unifiFirewallPolicy, "", " ") + log.Info(string(pretty)) + updatedPolicy, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallPolicy) + if err != nil { + log.Error(err, "Could not create firewall policy") + return ctrl.Result{}, err + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[index].TcpIpv6ID = updatedPolicy.ID + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + + } else { + log.Info(fmt.Sprintf("Firewall policy for ipv6 tcp %s to %s already exists", zoneCRDs.Items[i].Name, firewallGroup.Name)) + } + } + if len(firewallGroup.Status.ResolvedUDPPorts) > 0 { + policyname := "k8s-fw-" + firewallPolicy.Name + "-" + zoneCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv6-udp" + if _, found := unifiFirewallpolicyNames[policyname]; !found { + log.Info(fmt.Sprintf("Creating ipv6 udp firewallpolicy for %s to %s: %s", zoneCRDs.Items[i].Name, firewallGroup.Name, policyname)) + unifiFirewallPolicy := fillDefaultPolicy() + unifiFirewallPolicy.Name = policyname + unifiFirewallPolicy.Source.PortMatchingType = "ANY" + unifiFirewallPolicy.Source.ZoneID = zoneCRDs.Items[i].Spec.ID + unifiFirewallPolicy.Source.MatchingTarget = "ANY" + unifiFirewallPolicy.Protocol = "udp" + unifiFirewallPolicy.IPVersion = "IPV6" + unifiFirewallPolicy.Description = fmt.Sprintf("Allow udp IPV6 from %s to %s", zoneCRDs.Items[i].Name, firewallGroup.Name) + unifiFirewallPolicy.Destination.MatchingTargetType = "OBJECT" + unifiFirewallPolicy.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV6Object.ID + unifiFirewallPolicy.Destination.MatchingTarget = "IP" + unifiFirewallPolicy.Destination.PortMatchingType = "OBJECT" + unifiFirewallPolicy.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID + unifiFirewallPolicy.Destination.ZoneID = kubernetesZoneID + + log.Info(fmt.Sprintf("Trying to create firewall policy from zone %s to %s: %+v", zoneCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallPolicy)) + pretty, _ := json.MarshalIndent(unifiFirewallPolicy, "", " ") + log.Info(string(pretty)) + updatedPolicy, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallPolicy) + if err != nil { + log.Error(err, "Could not create firewall policy") + return ctrl.Result{}, err + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[index].UdpIpv6ID = updatedPolicy.ID + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + + } else { + log.Info(fmt.Sprintf("Firewall policy for ipv6 udp %s to %s already exists", zoneCRDs.Items[i].Name, firewallGroup.Name)) + } + } + } + } + } + } + for _, networkEntry := range firewallPolicy.Spec.Source.Networks { + namespace := defaultNs + if len(networkEntry.Namespace) > 0 { + namespace = networkEntry.Namespace + } + if i, found := networkCRDNames[namespace+"/"+networkEntry.Name]; found { + log.Info(fmt.Sprintf("Creating firewallpolicies for %s", networkCRDs.Items[i].Name)) + for _, firewallGroup := range myFirewallGroups { + index, found := firewallpolicyindex["network:"+networkCRDs.Items[i].Name+"/"+firewallGroup.Name] + if !found { + firewallPolicyEntry := unifiv1beta1.UnifiFirewallPolicyEntry{ + From: "zone:" + networkCRDs.Items[i].Name, + To: firewallGroup.Name, + TcpIpv4ID: "", + UdpIpv4ID: "", + TcpIpv6ID: "", + UdpIpv6ID: "", + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies = append(firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies, firewallPolicyEntry) + index = nextIndex + nextIndex = nextIndex + 1 + } + if len(firewallGroup.Status.ResolvedIPV4Addresses) > 0 { + if len(firewallGroup.Status.ResolvedTCPPorts) > 0 { + policyname := "k8s-fw-" + firewallPolicy.Name + "-" + networkCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv4-tcp" + if _, found := unifiFirewallpolicyNames[policyname]; !found { + log.Info(fmt.Sprintf("Creating ipv4 tcp firewallpolicy for %s to %s: %s", networkCRDs.Items[i].Name, firewallGroup.Name, policyname)) + unifiFirewallPolicy := fillDefaultPolicy() + unifiFirewallPolicy.Name = policyname + unifiFirewallPolicy.Source.NetworkIDs = []string{networkCRDs.Items[i].Spec.ID} + unifiFirewallPolicy.Source.PortMatchingType = "ANY" + unifiFirewallPolicy.Source.ZoneID = networkCRDs.Items[i].Status.FirewallZoneID + unifiFirewallPolicy.Source.MatchingTarget = "NETWORK" + unifiFirewallPolicy.Protocol = "tcp" + unifiFirewallPolicy.IPVersion = "IPV4" + unifiFirewallPolicy.Description = fmt.Sprintf("Allow tcp IPV4 from %s to %s", networkCRDs.Items[i].Name, firewallGroup.Name) + unifiFirewallPolicy.Destination.MatchingTargetType = "OBJECT" + unifiFirewallPolicy.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV4Object.ID + unifiFirewallPolicy.Destination.MatchingTarget = "IP" + unifiFirewallPolicy.Destination.PortMatchingType = "OBJECT" + unifiFirewallPolicy.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID + unifiFirewallPolicy.Destination.ZoneID = kubernetesZoneID + + log.Info(fmt.Sprintf("Trying to create firewall policy from network %s to %s: %+v", networkCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallPolicy)) + pretty, _ := json.MarshalIndent(unifiFirewallPolicy, "", " ") + log.Info(string(pretty)) + updatedPolicy, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallPolicy) + if err != nil { + log.Error(err, "Could not create firewall policy") + return ctrl.Result{}, err + } + + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[index].TcpIpv4ID = updatedPolicy.ID + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + } else { + log.Info(fmt.Sprintf("Firewall policy for ipv4 tcp %s to %s already exists", networkCRDs.Items[i].Name, firewallGroup.Name)) + } + } + if len(firewallGroup.Status.ResolvedUDPPorts) > 0 { + policyname := "k8s-fw-" + firewallPolicy.Name + "-" + networkCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv4-udp" + if _, found := unifiFirewallpolicyNames[policyname]; !found { + log.Info(fmt.Sprintf("Creating ipv4 udp firewallpolicy for %s to %s: %s", networkCRDs.Items[i].Name, firewallGroup.Name, policyname)) + unifiFirewallPolicy := fillDefaultPolicy() + unifiFirewallPolicy.Name = policyname + unifiFirewallPolicy.Source.NetworkIDs = []string{networkCRDs.Items[i].Spec.ID} + unifiFirewallPolicy.Source.PortMatchingType = "ANY" + unifiFirewallPolicy.Source.ZoneID = networkCRDs.Items[i].Status.FirewallZoneID + unifiFirewallPolicy.Source.MatchingTarget = "NETWORK" + unifiFirewallPolicy.Protocol = "udp" + unifiFirewallPolicy.IPVersion = "IPV4" + unifiFirewallPolicy.Description = fmt.Sprintf("Allow udp IPV4 from %s to %s", networkCRDs.Items[i].Name, firewallGroup.Name) + unifiFirewallPolicy.Destination.MatchingTargetType = "OBJECT" + unifiFirewallPolicy.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV4Object.ID + unifiFirewallPolicy.Destination.MatchingTarget = "IP" + unifiFirewallPolicy.Destination.PortMatchingType = "OBJECT" + unifiFirewallPolicy.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID + unifiFirewallPolicy.Destination.ZoneID = kubernetesZoneID + + log.Info(fmt.Sprintf("Trying to create firewall policy from network %s to %s: %+v", networkCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallPolicy)) + pretty, _ := json.MarshalIndent(unifiFirewallPolicy, "", " ") + log.Info(string(pretty)) + updatedPolicy, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallPolicy) + if err != nil { + log.Error(err, "Could not create firewall policy") + return ctrl.Result{}, err + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[index].UdpIpv4ID = updatedPolicy.ID + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + + } else { + log.Info(fmt.Sprintf("Firewall policy for ipv4 udp %s to %s already exists", networkCRDs.Items[i].Name, firewallGroup.Name)) + } + } + } + if len(firewallGroup.Status.ResolvedIPV6Addresses) > 0 { + if len(firewallGroup.Status.ResolvedTCPPorts) > 0 { + policyname := "k8s-fw-" + firewallPolicy.Name + "-" + networkCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv6-tcp" + if _, found := unifiFirewallpolicyNames[policyname]; !found { + log.Info(fmt.Sprintf("Creating ipv6 tcp firewallpolicy for %s to %s: %s", networkCRDs.Items[i].Name, firewallGroup.Name, policyname)) + unifiFirewallPolicy := fillDefaultPolicy() + unifiFirewallPolicy.Name = policyname + unifiFirewallPolicy.Source.NetworkIDs = []string{networkCRDs.Items[i].Spec.ID} + unifiFirewallPolicy.Source.PortMatchingType = "ANY" + unifiFirewallPolicy.Source.ZoneID = networkCRDs.Items[i].Status.FirewallZoneID + unifiFirewallPolicy.Source.MatchingTarget = "NETWORK" + unifiFirewallPolicy.Protocol = "tcp" + unifiFirewallPolicy.IPVersion = "IPV6" + unifiFirewallPolicy.Description = fmt.Sprintf("Allow tcp IPV6 from %s to %s", networkCRDs.Items[i].Name, firewallGroup.Name) + unifiFirewallPolicy.Destination.MatchingTargetType = "OBJECT" + unifiFirewallPolicy.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV6Object.ID + unifiFirewallPolicy.Destination.MatchingTarget = "IP" + unifiFirewallPolicy.Destination.PortMatchingType = "OBJECT" + unifiFirewallPolicy.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID + unifiFirewallPolicy.Destination.ZoneID = kubernetesZoneID + + log.Info(fmt.Sprintf("Trying to create firewall policy from network %s to %s: %+v", networkCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallPolicy)) + pretty, _ := json.MarshalIndent(unifiFirewallPolicy, "", " ") + log.Info(string(pretty)) + updatedPolicy, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallPolicy) + if err != nil { + log.Error(err, "Could not create firewall policy") + return ctrl.Result{}, err + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[index].TcpIpv6ID = updatedPolicy.ID + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + + } else { + log.Info(fmt.Sprintf("Firewall policy for ipv6 tcp %s to %s already exists", networkCRDs.Items[i].Name, firewallGroup.Name)) + } + } + if len(firewallGroup.Status.ResolvedUDPPorts) > 0 { + policyname := "k8s-fw-" + firewallPolicy.Name + "-" + networkCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv6-udp" + if _, found := unifiFirewallpolicyNames[policyname]; !found { + log.Info(fmt.Sprintf("Creating ipv6 udp firewallpolicy for %s to %s: %s", networkCRDs.Items[i].Name, firewallGroup.Name, policyname)) + unifiFirewallPolicy := fillDefaultPolicy() + unifiFirewallPolicy.Name = policyname + unifiFirewallPolicy.Source.NetworkIDs = []string{networkCRDs.Items[i].Spec.ID} + unifiFirewallPolicy.Source.PortMatchingType = "ANY" + unifiFirewallPolicy.Source.ZoneID = networkCRDs.Items[i].Status.FirewallZoneID + unifiFirewallPolicy.Source.MatchingTarget = "NETWORK" + unifiFirewallPolicy.Protocol = "udp" + unifiFirewallPolicy.IPVersion = "IPV6" + unifiFirewallPolicy.Description = fmt.Sprintf("Allow udp IPV6 from %s to %s", networkCRDs.Items[i].Name, firewallGroup.Name) + unifiFirewallPolicy.Destination.MatchingTargetType = "OBJECT" + unifiFirewallPolicy.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV6Object.ID + unifiFirewallPolicy.Destination.MatchingTarget = "IP" + unifiFirewallPolicy.Destination.PortMatchingType = "OBJECT" + unifiFirewallPolicy.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID + unifiFirewallPolicy.Destination.ZoneID = kubernetesZoneID + + log.Info(fmt.Sprintf("Trying to create firewall policy from network %s to %s: %+v", networkCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallPolicy)) + pretty, _ := json.MarshalIndent(unifiFirewallPolicy, "", " ") + log.Info(string(pretty)) + updatedPolicy, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallPolicy) + if err != nil { + log.Error(err, "Could not create firewall policy") + return ctrl.Result{}, err + } + firewallPolicy.Status.ResourcesManaged.UnifiFirewallPolicies[index].UdpIpv6ID = updatedPolicy.ID + if err := r.Status().Update(ctx, &firewallPolicy); err != nil { + return ctrl.Result{}, err + } + + } else { + log.Info(fmt.Sprintf("Firewall policy for ipv6 udp %s to %s already exists", networkCRDs.Items[i].Name, firewallGroup.Name)) + } + } + } + } + } + } + return ctrl.Result{}, nil +} + +func (r *FirewallPolicyReconciler) mapFirewallGroupToFirewallPolicies(ctx context.Context, obj client.Object) []ctrl.Request { + var requests []ctrl.Request + firewallGroup, ok := obj.(*unifiv1beta1.FirewallGroup) + if !ok { + return requests + } + + var allFirewallPolicies unifiv1beta1.FirewallPolicyList + + if err := r.List(ctx, &allFirewallPolicies); err != nil { + return nil + } + + for _, policy := range allFirewallPolicies.Items { + if policy.Spec.MatchFirewallGroupsInAllNamespaces || policy.Namespace == firewallGroup.Namespace { + annotationKey := "unifi.engen.priv.no/firewall-policy" + annotationVal := policy.Name + if val, ok := firewallGroup.Annotations[annotationKey]; ok && (annotationVal == "" || val == annotationVal) { + requests = append(requests, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Name: policy.Name, + Namespace: policy.Namespace, + }, + }) + } + } + } + + return requests +} + +func (r *FirewallPolicyReconciler) mapServiceToFirewallPolicies(ctx context.Context, obj client.Object) []ctrl.Request { + var requests []ctrl.Request + service, ok := obj.(*corev1.Service) + if !ok { + return requests + } + + var allFirewallPolicies unifiv1beta1.FirewallPolicyList + + if err := r.List(ctx, &allFirewallPolicies); err != nil { + return nil + } + + for _, policy := range allFirewallPolicies.Items { + if policy.Spec.MatchServicesInAllNamespaces || policy.Namespace == service.Namespace { + annotationKey := "unifi.engen.priv.no/firewall-policy" + annotationVal := policy.Name + if val, ok := service.Annotations[annotationKey]; ok && (annotationVal == "" || val == annotationVal) { + requests = append(requests, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Name: policy.Name, + Namespace: policy.Namespace, + }, + }) + } + } + } + + return requests +} + +// SetupWithManager sets up the controller with the Manager. +func (r *FirewallPolicyReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&unifiv1beta1.FirewallPolicy{}). + Named("firewallpolicy"). + Watches( + &corev1.Service{}, + handler.EnqueueRequestsFromMapFunc(r.mapServiceToFirewallPolicies), + ). + Watches( + &unifiv1beta1.FirewallGroup{}, + handler.EnqueueRequestsFromMapFunc(r.mapFirewallGroupToFirewallPolicies), + ). + Complete(r) +} diff --git a/internal/controller/firewallrule_controller_test.go b/internal/controller/firewallpolicy_controller_test.go similarity index 83% rename from internal/controller/firewallrule_controller_test.go rename to internal/controller/firewallpolicy_controller_test.go index e3f704d..6fb3d72 100644 --- a/internal/controller/firewallrule_controller_test.go +++ b/internal/controller/firewallpolicy_controller_test.go @@ -30,7 +30,7 @@ import ( unifiv1beta1 "github.com/vegardengen/unifi-network-operator/api/v1beta1" ) -var _ = Describe("FirewallRule Controller", func() { +var _ = Describe("FirewallPolicy Controller", func() { Context("When reconciling a resource", func() { const resourceName = "test-resource" @@ -40,13 +40,13 @@ var _ = Describe("FirewallRule Controller", func() { Name: resourceName, Namespace: "default", // TODO(user):Modify as needed } - firewallrule := &unifiv1beta1.FirewallRule{} + firewallpolicy := &unifiv1beta1.FirewallPolicy{} BeforeEach(func() { - By("creating the custom resource for the Kind FirewallRule") - err := k8sClient.Get(ctx, typeNamespacedName, firewallrule) + By("creating the custom resource for the Kind FirewallPolicy") + err := k8sClient.Get(ctx, typeNamespacedName, firewallpolicy) if err != nil && errors.IsNotFound(err) { - resource := &unifiv1beta1.FirewallRule{ + resource := &unifiv1beta1.FirewallPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: resourceName, Namespace: "default", @@ -59,16 +59,16 @@ var _ = Describe("FirewallRule Controller", func() { AfterEach(func() { // TODO(user): Cleanup logic after each test, like removing the resource instance. - resource := &unifiv1beta1.FirewallRule{} + resource := &unifiv1beta1.FirewallPolicy{} err := k8sClient.Get(ctx, typeNamespacedName, resource) Expect(err).NotTo(HaveOccurred()) - By("Cleanup the specific resource instance FirewallRule") + By("Cleanup the specific resource instance FirewallPolicy") Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) }) It("should successfully reconcile the resource", func() { By("Reconciling the created resource") - controllerReconciler := &FirewallRuleReconciler{ + controllerReconciler := &FirewallPolicyReconciler{ Client: k8sClient, Scheme: k8sClient.Scheme(), } diff --git a/internal/controller/firewallrule_controller.go b/internal/controller/firewallrule_controller.go deleted file mode 100644 index 7b4c27c..0000000 --- a/internal/controller/firewallrule_controller.go +++ /dev/null @@ -1,826 +0,0 @@ -/* -Copyright 2025 Vegard Engen. - -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 controller - -import ( - "context" - "fmt" - // "strings" - "encoding/json" - "time" - "strings" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/log" - - goUnifi "github.com/vegardengen/go-unifi/unifi" - unifiv1beta1 "github.com/vegardengen/unifi-network-operator/api/v1beta1" - "github.com/vegardengen/unifi-network-operator/internal/config" - "github.com/vegardengen/unifi-network-operator/internal/unifi" -) - -// FirewallRuleReconciler reconciles a FirewallRule object -type FirewallRuleReconciler struct { - client.Client - Scheme *runtime.Scheme - UnifiClient *unifi.UnifiClient - ConfigLoader *config.ConfigLoaderType -} - -const firewallRuleFinalizer = "finalizer.unifi.engen.priv.no/firewallrule" - -// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallrules,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallrules/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallrules/finalizers,verbs=update -// +kubebuilder:rbac:groups="",resources=configmaps,verbs=list;get;watch -// +kubebuilder:rbac:groups="",resources=services,verbs=list;get;watch - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the FirewallRule object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. -// -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.2/pkg/reconcile - -func fillDefaultRule() goUnifi.FirewallPolicy { - var firewallRule goUnifi.FirewallPolicy - firewallRule.Action = "ALLOW" - firewallRule.CreateAllowRespond = true - firewallRule.ConnectionStateType = "ALL" - firewallRule.ConnectionStates = []string{} - firewallRule.Destination = goUnifi.FirewallDestination{ - MatchOppositePorts: false, - MatchingTarget: "IP", - MatchingTargetType: "OBJECT", - } - firewallRule.Enabled = true - firewallRule.ICMPTypename = "ANY" - firewallRule.ICMPV6Typename = "ANY" - firewallRule.MatchIPSec = false - firewallRule.MatchOppositeProtocol = false - firewallRule.Predefined = false - firewallRule.Schedule = goUnifi.FirewallSchedule{ - Mode: "ALWAYS", - RepeatOnDays: []string{}, - TimeAllDay: false, - } - firewallRule.Source = goUnifi.FirewallSource{ - MatchMac: false, - MatchOppositePorts: false, - MatchOppositeNetworks: false, - } - - return firewallRule -} - -func (r *FirewallRuleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - log := log.FromContext(ctx) - - // TODO(user): your logic here - - cfg, err := r.ConfigLoader.GetConfig(ctx, "unifi-operator-config") - if err != nil { - return ctrl.Result{}, err - } - - defaultNs := cfg.Data["defaultNamespace"] - kubernetesZone := cfg.Data["kubernetesUnifiZone"] - var kubernetesZoneID string - log.Info(defaultNs) - log.Info(kubernetesZone) - - var firewallRule unifiv1beta1.FirewallRule - - if err := r.Get(ctx, req.NamespacedName, &firewallRule); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - log.Info(firewallRule.Spec.Name) - - if firewallRule.DeletionTimestamp != nil { - if controllerutil.ContainsFinalizer(&firewallRule, firewallRuleFinalizer) { - err := r.UnifiClient.Reauthenticate() - if err != nil { - return ctrl.Result{}, err - } - log.Info("Running finalizer logic for FirewallRule", "name", firewallRule.Name) - - if len(firewallRule.Status.ResourcesManaged.UnifiFirewallRules) > 0 { - for i, UnifiFirewallRule := range firewallRule.Status.ResourcesManaged.UnifiFirewallRules { - log.Info(fmt.Sprintf("From: %s to: %s TcpIpv4: %s UdpIpv4: %s TcpIpv6: %s UdpIpv6: %s", UnifiFirewallRule.From, UnifiFirewallRule.To, UnifiFirewallRule.TcpIpv4ID, UnifiFirewallRule.UdpIpv4ID, UnifiFirewallRule.TcpIpv6ID, UnifiFirewallRule.UdpIpv6ID)) - if len(UnifiFirewallRule.TcpIpv4ID) > 0 { - err := r.UnifiClient.Client.DeleteFirewallPolicy(context.Background(), r.UnifiClient.SiteID, UnifiFirewallRule.TcpIpv4ID) - if err != nil && !strings.Contains(err.Error(), "not found") { - } else { - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[i].TcpIpv4ID = "" - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - } - } - if len(UnifiFirewallRule.UdpIpv4ID) > 0 { - err := r.UnifiClient.Client.DeleteFirewallPolicy(context.Background(), r.UnifiClient.SiteID, UnifiFirewallRule.UdpIpv4ID) - if err != nil && !strings.Contains(err.Error(), "not found") { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } else { - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[i].UdpIpv4ID = "" - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - } - } - if len(UnifiFirewallRule.TcpIpv6ID) > 0 { - err := r.UnifiClient.Client.DeleteFirewallPolicy(context.Background(), r.UnifiClient.SiteID, UnifiFirewallRule.TcpIpv6ID) - if err != nil && !strings.Contains(err.Error(), "not found") { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } else { - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[i].TcpIpv6ID = "" - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - } - } - if len(UnifiFirewallRule.UdpIpv6ID) > 0 { - err := r.UnifiClient.Client.DeleteFirewallPolicy(context.Background(), r.UnifiClient.SiteID, UnifiFirewallRule.UdpIpv6ID) - if err != nil && !strings.Contains(err.Error(), "not found") { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } else { - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[i].UdpIpv6ID = "" - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - } - } - } - } - - if len(firewallRule.Status.ResourcesManaged.FirewallGroups) > 0 { - for i, firewallGroup := range firewallRule.Status.ResourcesManaged.FirewallGroups { - var firewallGroupCRD unifiv1beta1.FirewallGroup - if firewallGroup.Name != "" { - if err := r.Get(ctx, types.NamespacedName{Name: firewallGroup.Name, Namespace: firewallGroup.Namespace}, &firewallGroupCRD); err != nil { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - if err := r.Delete(ctx, &firewallGroupCRD); err != nil { - log.Error(err, "Could not delete firewall group") - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - firewallRule.Status.ResourcesManaged.FirewallGroups[i].Name = "" - firewallRule.Status.ResourcesManaged.FirewallGroups[i].Namespace = "" - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - } - } - } - controllerutil.RemoveFinalizer(&firewallRule, firewallRuleFinalizer) - if err := r.Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - - log.Info("Successfully finalized FirewallGroup") - } - return ctrl.Result{}, nil - } - if !controllerutil.ContainsFinalizer(&firewallRule, firewallRuleFinalizer) { - controllerutil.AddFinalizer(&firewallRule, firewallRuleFinalizer) - if err := r.Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - } - - firewallruleindex := make(map[string]int) - - nextIndex := 0 - if firewallRule.Status.ResourcesManaged == nil { - firewallGroupsManaged := []unifiv1beta1.FirewallGroupEntry{} - unifiFirewallRules := []unifiv1beta1.UnifiFirewallRuleEntry{} - firewallRule.Status.ResourcesManaged = &unifiv1beta1.FirewallRuleResourcesManaged{ - UnifiFirewallRules: unifiFirewallRules, - FirewallGroups: firewallGroupsManaged, - } - } else { - for index, firewallRuleEntry := range firewallRule.Status.ResourcesManaged.UnifiFirewallRules { - firewallruleindex[firewallRuleEntry.From+"/"+firewallRuleEntry.To] = index - nextIndex = nextIndex + 1 - } - } - err = r.UnifiClient.Reauthenticate() - if err != nil { - return ctrl.Result{}, err - } - - var zoneCRDs unifiv1beta1.FirewallZoneList - var networkCRDs unifiv1beta1.NetworkconfigurationList - - err = r.List(ctx, &zoneCRDs) - if err != nil { - log.Error(err, "Could not list firewall zones") - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - - zoneCRDNames := make(map[string]int) - - for i, zoneCRD := range zoneCRDs.Items { - namespace := defaultNs - if len(zoneCRD.Namespace) > 0 { - namespace = zoneCRD.Namespace - } - if kubernetesZone == zoneCRD.Name { - kubernetesZoneID = zoneCRD.Spec.ID - log.Info(fmt.Sprintf("Zone for kubernetes resources: %s with ID %s", kubernetesZone, kubernetesZoneID)) - } - zoneCRDNames[namespace+"/"+zoneCRD.Name] = i - } - - err = r.List(ctx, &networkCRDs) - if err != nil { - log.Error(err, "Could not list networks") - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - - networkCRDNames := make(map[string]int) - - for i, networkCRD := range networkCRDs.Items { - namespace := defaultNs - if len(networkCRD.Namespace) > 0 { - namespace = networkCRD.Namespace - } - networkCRDNames[namespace+"/"+networkCRD.Name] = i - } - - destination_services := make(map[string]struct{}) - destination_groups := make(map[string]struct{}) - - for _, dest_group := range firewallRule.Spec.Destination.FirewallGroups { - namespace := defaultNs - if len(dest_group.Namespace) > 0 { - namespace = dest_group.Namespace - } - destination_groups[namespace+"/"+dest_group.Name] = struct{}{} - } - for _, dest_service := range firewallRule.Spec.Destination.Services { - namespace := defaultNs - if len(dest_service.Namespace) > 0 { - namespace = dest_service.Namespace - } - destination_services[namespace+"/"+dest_service.Name] = struct{}{} - } - log.Info(fmt.Sprintf("%+v", destination_services)) - var firewallGroupCRDs unifiv1beta1.FirewallGroupList - var myFirewallGroups []unifiv1beta1.FirewallGroup - if err = r.List(ctx, &firewallGroupCRDs); err != nil { - log.Error(err, "Failed to list firewall groups") - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - - for _, firewallGroup := range firewallGroupCRDs.Items { - if val, found := firewallGroup.Annotations["unifi.engen.priv.no/firewall-rule"]; found && val == firewallRule.Name { - myFirewallGroups = append(myFirewallGroups, firewallGroup) - } else if _, found := destination_groups[firewallGroup.Namespace+"/"+firewallGroup.Name]; found { - myFirewallGroups = append(myFirewallGroups, firewallGroup) - } - } - myFirewallGroupNames := make(map[string]struct{}) - for _, firewallGroup := range myFirewallGroups { - myFirewallGroupNames[firewallGroup.Name] = struct{}{} - } - var serviceCRDs corev1.ServiceList - var myServices []corev1.Service - if err = r.List(ctx, &serviceCRDs); err != nil { - log.Error(err, "Failed to list services") - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } - for _, service := range serviceCRDs.Items { - skipService := false - if val, found := service.Annotations["unifi.engen.priv.no/firewall-group"]; found { - if _, found := myFirewallGroupNames[val]; found { - skipService = true - } - } - if val, found := service.Annotations["unifi.engen.priv.no/firewall-rule"]; found && val == firewallRule.Name && !skipService { - myServices = append(myServices, service) - } else if _, found := destination_services[service.Namespace+"/"+service.Name]; found && !skipService { - myServices = append(myServices, service) - } - } - - for _, service := range myServices { - log.Info(fmt.Sprintf("Should handle service %s", service.Name)) - var firewallGroupCRD unifiv1beta1.FirewallGroup - if err := r.Get(ctx, types.NamespacedName{ - Name: toKubeName("k8s-auto" + "_" + service.Namespace + "/" + service.Name), - Namespace: firewallRule.Namespace, - }, &firewallGroupCRD); err == nil { - myFirewallGroups = append(myFirewallGroups, firewallGroupCRD) - } else { - log.Info("Going to create firewall group") - var manualServices []unifiv1beta1.ServiceEntry - manualServices = append(manualServices, unifiv1beta1.ServiceEntry{ - Name: service.Name, - Namespace: service.Namespace, - }) - createdFirewallGroupCRD := &unifiv1beta1.FirewallGroup{ - ObjectMeta: ctrl.ObjectMeta{ - Name: toKubeName("k8s-auto" + "_" + service.Namespace + "/" + service.Name), - Namespace: firewallRule.Namespace, - }, - Spec: unifiv1beta1.FirewallGroupSpec{ - Name: "auto-" + service.Namespace + "/" + service.Name, - AutoCreatedFrom: unifiv1beta1.FirewallRuleEntry{ - Name: firewallRule.Name, - Namespace: firewallRule.Namespace, - }, - ManualServices: manualServices, - MatchServicesInAllNamespaces: true, - }, - } - log.Info(fmt.Sprintf("%+v", createdFirewallGroupCRD)) - if err := r.Create(ctx, createdFirewallGroupCRD); err != nil { - log.Error(err, fmt.Sprintf("Failed to create %s", createdFirewallGroupCRD.Name)) - return ctrl.Result{RequeueAfter: 10 * time.Minute}, err - } else { - time.Sleep(10 * time.Second) - _ = r.Get(ctx, types.NamespacedName{Name: createdFirewallGroupCRD.Name, Namespace: createdFirewallGroupCRD.Namespace}, &firewallGroupCRD) - } - log.Info(fmt.Sprintf("Adding %+v", firewallGroupCRD)) - myFirewallGroups = append(myFirewallGroups, firewallGroupCRD) - found := false - for _, managedFirewallGroup := range firewallRule.Status.ResourcesManaged.FirewallGroups { - if managedFirewallGroup.Name == firewallGroupCRD.Name && managedFirewallGroup.Namespace == firewallGroupCRD.Namespace { - found = true - } - } - if !found { - firewallRule.Status.ResourcesManaged.FirewallGroups = append(firewallRule.Status.ResourcesManaged.FirewallGroups, unifiv1beta1.FirewallGroupEntry{Name: firewallGroupCRD.Name, Namespace: firewallGroupCRD.Namespace}) - if err := r.Status().Update(ctx, &firewallRule); err != nil { - log.Error(err, "Failed to update status with added firewallgroup") - } - } - - } - } - unifi_firewall_rules, err := r.UnifiClient.Client.ListFirewallPolicy(context.Background(), r.UnifiClient.SiteID) - if err != nil { - log.Error(err, "Could not list firewall rules") - return ctrl.Result{}, err - } - unifiFirewallruleNames := make(map[string]struct{}) - for _, unifi_firewall_rule := range unifi_firewall_rules { - unifiFirewallruleNames[unifi_firewall_rule.Name] = struct{}{} - } - log.Info(fmt.Sprintf("Number of firewall rules: %d", len(unifi_firewall_rules))) - - for _, zoneEntry := range firewallRule.Spec.Source.FirewallZones { - namespace := defaultNs - if len(zoneEntry.Namespace) > 0 { - namespace = zoneEntry.Namespace - } - if i, found := zoneCRDNames[namespace+"/"+zoneEntry.Name]; found { - log.Info(fmt.Sprintf("Creating firewallrules for %s", zoneCRDs.Items[i].Name)) - for _, firewallGroup := range myFirewallGroups { - found := false - index, found := firewallruleindex["zone:"+zoneCRDs.Items[i].Name+"/"+firewallGroup.Name] - if !found { - firewallRuleEntry := unifiv1beta1.UnifiFirewallRuleEntry{ - From: "zone:" + zoneCRDs.Items[i].Name, - To: firewallGroup.Name, - TcpIpv4ID: "", - UdpIpv4ID: "", - TcpIpv6ID: "", - UdpIpv6ID: "", - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules = append(firewallRule.Status.ResourcesManaged.UnifiFirewallRules, firewallRuleEntry) - index = nextIndex - nextIndex = nextIndex + 1 - } - - if len(firewallGroup.Status.ResolvedIPV4Addresses) > 0 { - if len(firewallGroup.Status.ResolvedTCPPorts) > 0 { - rulename := "k8s-fw-" + firewallRule.Name + "-" + zoneCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv4-tcp" - if _, found := unifiFirewallruleNames[rulename]; !found { - log.Info(fmt.Sprintf("Creating ipv4 tcp firewallrule for %s to %s: %s", zoneCRDs.Items[i].Name, firewallGroup.Name, rulename)) - unifiFirewallRule := fillDefaultRule() - unifiFirewallRule.Name = rulename - unifiFirewallRule.Source.PortMatchingType = "ANY" - unifiFirewallRule.Source.ZoneID = zoneCRDs.Items[i].Spec.ID - unifiFirewallRule.Source.MatchingTarget = "ANY" - unifiFirewallRule.Protocol = "tcp" - unifiFirewallRule.IPVersion = "IPV4" - unifiFirewallRule.Description = fmt.Sprintf("Allow tcp IPV4 from %s to %s", zoneCRDs.Items[i].Name, firewallGroup.Name) - unifiFirewallRule.Destination.MatchingTargetType = "OBJECT" - unifiFirewallRule.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV4Object.ID - unifiFirewallRule.Destination.MatchingTarget = "IP" - unifiFirewallRule.Destination.PortMatchingType = "OBJECT" - unifiFirewallRule.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID - unifiFirewallRule.Destination.ZoneID = kubernetesZoneID - - log.Info(fmt.Sprintf("Trying to create firewall rule from zone %s to %s: %+v", zoneCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallRule)) - pretty, _ := json.MarshalIndent(unifiFirewallRule, "", " ") - log.Info(string(pretty)) - updatedRule, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallRule) - if err != nil { - log.Error(err, "Could not create firewall policy") - return ctrl.Result{}, err - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[index].TcpIpv4ID = updatedRule.ID - if err = r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - } else { - log.Info(fmt.Sprintf("Firewall rule for ipv4 tcp %s to %s already exists", zoneCRDs.Items[i].Name, firewallGroup.Name)) - } - } - if len(firewallGroup.Status.ResolvedUDPPorts) > 0 { - rulename := "k8s-fw-" + firewallRule.Name + "-" + zoneCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv4-udp" - if _, found := unifiFirewallruleNames[rulename]; !found { - log.Info(fmt.Sprintf("Creating ipv4 udp firewallrule for %s to %s: %s", zoneCRDs.Items[i].Name, firewallGroup.Name, rulename)) - unifiFirewallRule := fillDefaultRule() - unifiFirewallRule.Name = rulename - unifiFirewallRule.Source.PortMatchingType = "ANY" - unifiFirewallRule.Source.ZoneID = zoneCRDs.Items[i].Spec.ID - unifiFirewallRule.Source.MatchingTarget = "ANY" - unifiFirewallRule.Protocol = "udp" - unifiFirewallRule.IPVersion = "IPV4" - unifiFirewallRule.Description = fmt.Sprintf("Allow udp IPV4 from %s to %s", zoneCRDs.Items[i].Name, firewallGroup.Name) - unifiFirewallRule.Destination.MatchingTargetType = "OBJECT" - unifiFirewallRule.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV4Object.ID - unifiFirewallRule.Destination.MatchingTarget = "IP" - unifiFirewallRule.Destination.PortMatchingType = "OBJECT" - unifiFirewallRule.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID - unifiFirewallRule.Destination.ZoneID = kubernetesZoneID - - log.Info(fmt.Sprintf("Trying to create firewall rule from zone %s to %s: %+v", zoneCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallRule)) - pretty, _ := json.MarshalIndent(unifiFirewallRule, "", " ") - log.Info(string(pretty)) - updatedRule, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallRule) - if err != nil { - log.Error(err, "Could not create firewall policy") - return ctrl.Result{}, err - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[index].UdpIpv4ID = updatedRule.ID - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - - } else { - log.Info(fmt.Sprintf("Firewall rule for ipv4 udp %s to %s already exists", zoneCRDs.Items[i].Name, firewallGroup.Name)) - } - } - } - if len(firewallGroup.Status.ResolvedIPV6Addresses) > 0 { - if len(firewallGroup.Status.ResolvedTCPPorts) > 0 { - rulename := "k8s-fw-" + firewallRule.Name + "-" + zoneCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv6-tcp" - if _, found := unifiFirewallruleNames[rulename]; !found { - log.Info(fmt.Sprintf("Creating ipv6 tcp firewallrule for %s to %s: %s", zoneCRDs.Items[i].Name, firewallGroup.Name, rulename)) - unifiFirewallRule := fillDefaultRule() - unifiFirewallRule.Name = rulename - unifiFirewallRule.Source.PortMatchingType = "ANY" - unifiFirewallRule.Source.ZoneID = zoneCRDs.Items[i].Spec.ID - unifiFirewallRule.Source.MatchingTarget = "ANY" - unifiFirewallRule.Protocol = "tcp" - unifiFirewallRule.IPVersion = "IPV6" - unifiFirewallRule.Description = fmt.Sprintf("Allow tcp IPV6 from %s to %s", zoneCRDs.Items[i].Name, firewallGroup.Name) - unifiFirewallRule.Destination.MatchingTargetType = "OBJECT" - unifiFirewallRule.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV6Object.ID - unifiFirewallRule.Destination.MatchingTarget = "IP" - unifiFirewallRule.Destination.PortMatchingType = "OBJECT" - unifiFirewallRule.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID - unifiFirewallRule.Destination.ZoneID = kubernetesZoneID - - log.Info(fmt.Sprintf("Trying to create firewall rule from zone %s to %s: %+v", zoneCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallRule)) - pretty, _ := json.MarshalIndent(unifiFirewallRule, "", " ") - log.Info(string(pretty)) - updatedRule, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallRule) - if err != nil { - log.Error(err, "Could not create firewall policy") - return ctrl.Result{}, err - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[index].TcpIpv6ID = updatedRule.ID - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - - } else { - log.Info(fmt.Sprintf("Firewall rule for ipv6 tcp %s to %s already exists", zoneCRDs.Items[i].Name, firewallGroup.Name)) - } - } - if len(firewallGroup.Status.ResolvedUDPPorts) > 0 { - rulename := "k8s-fw-" + firewallRule.Name + "-" + zoneCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv6-udp" - if _, found := unifiFirewallruleNames[rulename]; !found { - log.Info(fmt.Sprintf("Creating ipv6 udp firewallrule for %s to %s: %s", zoneCRDs.Items[i].Name, firewallGroup.Name, rulename)) - unifiFirewallRule := fillDefaultRule() - unifiFirewallRule.Name = rulename - unifiFirewallRule.Source.PortMatchingType = "ANY" - unifiFirewallRule.Source.ZoneID = zoneCRDs.Items[i].Spec.ID - unifiFirewallRule.Source.MatchingTarget = "ANY" - unifiFirewallRule.Protocol = "udp" - unifiFirewallRule.IPVersion = "IPV6" - unifiFirewallRule.Description = fmt.Sprintf("Allow udp IPV6 from %s to %s", zoneCRDs.Items[i].Name, firewallGroup.Name) - unifiFirewallRule.Destination.MatchingTargetType = "OBJECT" - unifiFirewallRule.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV6Object.ID - unifiFirewallRule.Destination.MatchingTarget = "IP" - unifiFirewallRule.Destination.PortMatchingType = "OBJECT" - unifiFirewallRule.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID - unifiFirewallRule.Destination.ZoneID = kubernetesZoneID - - log.Info(fmt.Sprintf("Trying to create firewall rule from zone %s to %s: %+v", zoneCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallRule)) - pretty, _ := json.MarshalIndent(unifiFirewallRule, "", " ") - log.Info(string(pretty)) - updatedRule, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallRule) - if err != nil { - log.Error(err, "Could not create firewall policy") - return ctrl.Result{}, err - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[index].UdpIpv6ID = updatedRule.ID - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - - } else { - log.Info(fmt.Sprintf("Firewall rule for ipv6 udp %s to %s already exists", zoneCRDs.Items[i].Name, firewallGroup.Name)) - } - } - } - } - } - } - for _, networkEntry := range firewallRule.Spec.Source.Networks { - namespace := defaultNs - if len(networkEntry.Namespace) > 0 { - namespace = networkEntry.Namespace - } - if i, found := networkCRDNames[namespace+"/"+networkEntry.Name]; found { - log.Info(fmt.Sprintf("Creating firewallrules for %s", networkCRDs.Items[i].Name)) - for _, firewallGroup := range myFirewallGroups { - index, found := firewallruleindex["network:"+networkCRDs.Items[i].Name+"/"+firewallGroup.Name] - if !found { - firewallRuleEntry := unifiv1beta1.UnifiFirewallRuleEntry{ - From: "zone:" + networkCRDs.Items[i].Name, - To: firewallGroup.Name, - TcpIpv4ID: "", - UdpIpv4ID: "", - TcpIpv6ID: "", - UdpIpv6ID: "", - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules = append(firewallRule.Status.ResourcesManaged.UnifiFirewallRules, firewallRuleEntry) - index = nextIndex - nextIndex = nextIndex + 1 - } - if len(firewallGroup.Status.ResolvedIPV4Addresses) > 0 { - if len(firewallGroup.Status.ResolvedTCPPorts) > 0 { - rulename := "k8s-fw-" + firewallRule.Name + "-" + networkCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv4-tcp" - if _, found := unifiFirewallruleNames[rulename]; !found { - log.Info(fmt.Sprintf("Creating ipv4 tcp firewallrule for %s to %s: %s", networkCRDs.Items[i].Name, firewallGroup.Name, rulename)) - unifiFirewallRule := fillDefaultRule() - unifiFirewallRule.Name = rulename - unifiFirewallRule.Source.NetworkIDs = []string{networkCRDs.Items[i].Spec.ID} - unifiFirewallRule.Source.PortMatchingType = "ANY" - unifiFirewallRule.Source.ZoneID = networkCRDs.Items[i].Status.FirewallZoneID - unifiFirewallRule.Source.MatchingTarget = "NETWORK" - unifiFirewallRule.Protocol = "tcp" - unifiFirewallRule.IPVersion = "IPV4" - unifiFirewallRule.Description = fmt.Sprintf("Allow tcp IPV4 from %s to %s", networkCRDs.Items[i].Name, firewallGroup.Name) - unifiFirewallRule.Destination.MatchingTargetType = "OBJECT" - unifiFirewallRule.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV4Object.ID - unifiFirewallRule.Destination.MatchingTarget = "IP" - unifiFirewallRule.Destination.PortMatchingType = "OBJECT" - unifiFirewallRule.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID - unifiFirewallRule.Destination.ZoneID = kubernetesZoneID - - log.Info(fmt.Sprintf("Trying to create firewall rule from network %s to %s: %+v", networkCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallRule)) - pretty, _ := json.MarshalIndent(unifiFirewallRule, "", " ") - log.Info(string(pretty)) - updatedRule, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallRule) - if err != nil { - log.Error(err, "Could not create firewall policy") - return ctrl.Result{}, err - } - - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[index].TcpIpv4ID = updatedRule.ID - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - } else { - log.Info(fmt.Sprintf("Firewall rule for ipv4 tcp %s to %s already exists", networkCRDs.Items[i].Name, firewallGroup.Name)) - } - } - if len(firewallGroup.Status.ResolvedUDPPorts) > 0 { - rulename := "k8s-fw-" + firewallRule.Name + "-" + networkCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv4-udp" - if _, found := unifiFirewallruleNames[rulename]; !found { - log.Info(fmt.Sprintf("Creating ipv4 udp firewallrule for %s to %s: %s", networkCRDs.Items[i].Name, firewallGroup.Name, rulename)) - unifiFirewallRule := fillDefaultRule() - unifiFirewallRule.Name = rulename - unifiFirewallRule.Source.NetworkIDs = []string{networkCRDs.Items[i].Spec.ID} - unifiFirewallRule.Source.PortMatchingType = "ANY" - unifiFirewallRule.Source.ZoneID = networkCRDs.Items[i].Status.FirewallZoneID - unifiFirewallRule.Source.MatchingTarget = "NETWORK" - unifiFirewallRule.Protocol = "udp" - unifiFirewallRule.IPVersion = "IPV4" - unifiFirewallRule.Description = fmt.Sprintf("Allow udp IPV4 from %s to %s", networkCRDs.Items[i].Name, firewallGroup.Name) - unifiFirewallRule.Destination.MatchingTargetType = "OBJECT" - unifiFirewallRule.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV4Object.ID - unifiFirewallRule.Destination.MatchingTarget = "IP" - unifiFirewallRule.Destination.PortMatchingType = "OBJECT" - unifiFirewallRule.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID - unifiFirewallRule.Destination.ZoneID = kubernetesZoneID - - log.Info(fmt.Sprintf("Trying to create firewall rule from network %s to %s: %+v", networkCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallRule)) - pretty, _ := json.MarshalIndent(unifiFirewallRule, "", " ") - log.Info(string(pretty)) - updatedRule, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallRule) - if err != nil { - log.Error(err, "Could not create firewall policy") - return ctrl.Result{}, err - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[index].UdpIpv4ID = updatedRule.ID - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - - } else { - log.Info(fmt.Sprintf("Firewall rule for ipv4 udp %s to %s already exists", networkCRDs.Items[i].Name, firewallGroup.Name)) - } - } - } - if len(firewallGroup.Status.ResolvedIPV6Addresses) > 0 { - if len(firewallGroup.Status.ResolvedTCPPorts) > 0 { - rulename := "k8s-fw-" + firewallRule.Name + "-" + networkCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv6-tcp" - if _, found := unifiFirewallruleNames[rulename]; !found { - log.Info(fmt.Sprintf("Creating ipv6 tcp firewallrule for %s to %s: %s", networkCRDs.Items[i].Name, firewallGroup.Name, rulename)) - unifiFirewallRule := fillDefaultRule() - unifiFirewallRule.Name = rulename - unifiFirewallRule.Source.NetworkIDs = []string{networkCRDs.Items[i].Spec.ID} - unifiFirewallRule.Source.PortMatchingType = "ANY" - unifiFirewallRule.Source.ZoneID = networkCRDs.Items[i].Status.FirewallZoneID - unifiFirewallRule.Source.MatchingTarget = "NETWORK" - unifiFirewallRule.Protocol = "tcp" - unifiFirewallRule.IPVersion = "IPV6" - unifiFirewallRule.Description = fmt.Sprintf("Allow tcp IPV6 from %s to %s", networkCRDs.Items[i].Name, firewallGroup.Name) - unifiFirewallRule.Destination.MatchingTargetType = "OBJECT" - unifiFirewallRule.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV6Object.ID - unifiFirewallRule.Destination.MatchingTarget = "IP" - unifiFirewallRule.Destination.PortMatchingType = "OBJECT" - unifiFirewallRule.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.TCPPortsObject.ID - unifiFirewallRule.Destination.ZoneID = kubernetesZoneID - - log.Info(fmt.Sprintf("Trying to create firewall rule from network %s to %s: %+v", networkCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallRule)) - pretty, _ := json.MarshalIndent(unifiFirewallRule, "", " ") - log.Info(string(pretty)) - updatedRule, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallRule) - if err != nil { - log.Error(err, "Could not create firewall policy") - return ctrl.Result{}, err - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[index].TcpIpv6ID = updatedRule.ID - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - - } else { - log.Info(fmt.Sprintf("Firewall rule for ipv6 tcp %s to %s already exists", networkCRDs.Items[i].Name, firewallGroup.Name)) - } - } - if len(firewallGroup.Status.ResolvedUDPPorts) > 0 { - rulename := "k8s-fw-" + firewallRule.Name + "-" + networkCRDs.Items[i].Name + "-" + firewallGroup.Name + "-ipv6-udp" - if _, found := unifiFirewallruleNames[rulename]; !found { - log.Info(fmt.Sprintf("Creating ipv6 udp firewallrule for %s to %s: %s", networkCRDs.Items[i].Name, firewallGroup.Name, rulename)) - unifiFirewallRule := fillDefaultRule() - unifiFirewallRule.Name = rulename - unifiFirewallRule.Source.NetworkIDs = []string{networkCRDs.Items[i].Spec.ID} - unifiFirewallRule.Source.PortMatchingType = "ANY" - unifiFirewallRule.Source.ZoneID = networkCRDs.Items[i].Status.FirewallZoneID - unifiFirewallRule.Source.MatchingTarget = "NETWORK" - unifiFirewallRule.Protocol = "udp" - unifiFirewallRule.IPVersion = "IPV6" - unifiFirewallRule.Description = fmt.Sprintf("Allow udp IPV6 from %s to %s", networkCRDs.Items[i].Name, firewallGroup.Name) - unifiFirewallRule.Destination.MatchingTargetType = "OBJECT" - unifiFirewallRule.Destination.IPGroupID = firewallGroup.Status.ResourcesManaged.IPV6Object.ID - unifiFirewallRule.Destination.MatchingTarget = "IP" - unifiFirewallRule.Destination.PortMatchingType = "OBJECT" - unifiFirewallRule.Destination.PortGroupID = firewallGroup.Status.ResourcesManaged.UDPPortsObject.ID - unifiFirewallRule.Destination.ZoneID = kubernetesZoneID - - log.Info(fmt.Sprintf("Trying to create firewall rule from network %s to %s: %+v", networkCRDs.Items[i].Name, firewallGroup.Name, unifiFirewallRule)) - pretty, _ := json.MarshalIndent(unifiFirewallRule, "", " ") - log.Info(string(pretty)) - updatedRule, err := r.UnifiClient.Client.CreateFirewallPolicy(context.Background(), r.UnifiClient.SiteID, &unifiFirewallRule) - if err != nil { - log.Error(err, "Could not create firewall policy") - return ctrl.Result{}, err - } - firewallRule.Status.ResourcesManaged.UnifiFirewallRules[index].UdpIpv6ID = updatedRule.ID - if err := r.Status().Update(ctx, &firewallRule); err != nil { - return ctrl.Result{}, err - } - - } else { - log.Info(fmt.Sprintf("Firewall rule for ipv6 udp %s to %s already exists", networkCRDs.Items[i].Name, firewallGroup.Name)) - } - } - } - } - } - } - return ctrl.Result{}, nil -} - -func (r *FirewallRuleReconciler) mapFirewallGroupToFirewallRules(ctx context.Context, obj client.Object) []ctrl.Request { - var requests []ctrl.Request - firewallGroup, ok := obj.(*unifiv1beta1.FirewallGroup) - if !ok { - return requests - } - - var allFirewallRules unifiv1beta1.FirewallRuleList - - if err := r.List(ctx, &allFirewallRules); err != nil { - return nil - } - - for _, rule := range allFirewallRules.Items { - if rule.Spec.MatchFirewallGroupsInAllNamespaces || rule.Namespace == firewallGroup.Namespace { - annotationKey := "unifi.engen.priv.no/firewall-rule" - annotationVal := rule.Name - if val, ok := firewallGroup.Annotations[annotationKey]; ok && (annotationVal == "" || val == annotationVal) { - requests = append(requests, ctrl.Request{ - NamespacedName: types.NamespacedName{ - Name: rule.Name, - Namespace: rule.Namespace, - }, - }) - } - } - } - - return requests -} - -func (r *FirewallRuleReconciler) mapServiceToFirewallRules(ctx context.Context, obj client.Object) []ctrl.Request { - var requests []ctrl.Request - service, ok := obj.(*corev1.Service) - if !ok { - return requests - } - - var allFirewallRules unifiv1beta1.FirewallRuleList - - if err := r.List(ctx, &allFirewallRules); err != nil { - return nil - } - - for _, rule := range allFirewallRules.Items { - if rule.Spec.MatchServicesInAllNamespaces || rule.Namespace == service.Namespace { - annotationKey := "unifi.engen.priv.no/firewall-rule" - annotationVal := rule.Name - if val, ok := service.Annotations[annotationKey]; ok && (annotationVal == "" || val == annotationVal) { - requests = append(requests, ctrl.Request{ - NamespacedName: types.NamespacedName{ - Name: rule.Name, - Namespace: rule.Namespace, - }, - }) - } - } - } - - return requests -} - -// SetupWithManager sets up the controller with the Manager. -func (r *FirewallRuleReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&unifiv1beta1.FirewallRule{}). - Named("firewallrule"). - Watches( - &corev1.Service{}, - handler.EnqueueRequestsFromMapFunc(r.mapServiceToFirewallRules), - ). - Watches( - &unifiv1beta1.FirewallGroup{}, - handler.EnqueueRequestsFromMapFunc(r.mapFirewallGroupToFirewallRules), - ). - Complete(r) -}