diff --git a/src/conf/local-file.yaml b/src/conf/local-file.yaml index 103e102f..04d7bf95 100644 --- a/src/conf/local-file.yaml +++ b/src/conf/local-file.yaml @@ -2,10 +2,10 @@ application: name: knoxautopolicy network: operation-mode: 1 # 1: cronjob | 2: one-time-job - operation-trigger: 5 + operation-trigger: 100 cron-job-time-interval: "0h0m10s" # format: XhYmZs network-log-limit: 10000 - network-log-from: "kubearmor" # db|hubble|feed-consumer|kubearmor + network-log-from: "hubble" # db|hubble|feed-consumer|kubearmor #network-log-file: "/home/rahul/feeds.json" # file path network-policy-to: "db" # db, file network-policy-dir: "./" diff --git a/src/networkpolicy/deduplicator.go b/src/networkpolicy/deduplicator.go index b45ebbb9..8535f63f 100644 --- a/src/networkpolicy/deduplicator.go +++ b/src/networkpolicy/deduplicator.go @@ -974,13 +974,15 @@ func UpdateDuplicatedPolicy(existingPolicies []types.KnoxNetworkPolicy, discover for _, policy := range existIngressPolicies { if policy.Metadata["status"] == "updated" { - delete(policy.Metadata, "status") + policy.Metadata["status"] = "latest" + //delete(policy.Metadata, "status") updatedPolicies = append(updatedPolicies, policy) } } for _, policy := range existEgressPolicies { if policy.Metadata["status"] == "updated" { - delete(policy.Metadata, "status") + policy.Metadata["status"] = "latest" + //delete(policy.Metadata, "status") updatedPolicies = append(updatedPolicies, policy) } } diff --git a/src/networkpolicy/helperFunctions.go b/src/networkpolicy/helperFunctions.go index 9675d6df..54aaee4a 100644 --- a/src/networkpolicy/helperFunctions.go +++ b/src/networkpolicy/helperFunctions.go @@ -13,6 +13,7 @@ import ( "github.com/clarketm/json" "github.com/accuknox/auto-policy-discovery/src/cluster" + "github.com/accuknox/auto-policy-discovery/src/config" "github.com/accuknox/auto-policy-discovery/src/libs" "github.com/accuknox/auto-policy-discovery/src/plugin" wpb "github.com/accuknox/auto-policy-discovery/src/protobuf/v1/worker" @@ -797,7 +798,8 @@ func GetNetPolicy(cluster, namespace, policyType string) *wpb.WorkerResponse { } response.K8SNetworkpolicy = nil } else if strings.Contains(policyType, "generic") { - policies := plugin.ConvertKnoxNetPolicyToK8sNetworkPolicy(cluster, namespace) + knoxNetPolicies := libs.GetNetworkPolicies(config.CurrentCfg.ConfigDB, cluster, namespace, "latest", "", "") + policies := plugin.ConvertKnoxNetPolicyToK8sNetworkPolicy(cluster, namespace, knoxNetPolicies) for i := range policies { genericNetPol := wpb.Policy{} diff --git a/src/networkpolicy/networkPolicy.go b/src/networkpolicy/networkPolicy.go index ecadfba7..8997033f 100644 --- a/src/networkpolicy/networkPolicy.go +++ b/src/networkpolicy/networkPolicy.go @@ -1554,6 +1554,38 @@ func mergeNetworkPolicies(existPolicy types.KnoxNetworkPolicy, policies []types. return mergeEgressPolicies(existPolicy, policies) } +func checkIfIngressEgressPortExist(polType string, newToPort types.SpecPort, mergedPolicy types.KnoxNetworkPolicy) bool { + isExist := false + + if polType == "EGRESS" { + for _, existEgress := range mergedPolicy.Spec.Egress { + if len(existEgress.ToPorts) == 0 { + continue + } + existToPort := existEgress.ToPorts[0] + + if existToPort == newToPort { + isExist = true + break + } + } + } else if polType == "INGRESS" { + for _, existIngress := range mergedPolicy.Spec.Ingress { + if len(existIngress.ToPorts) == 0 { + continue + } + existToPort := existIngress.ToPorts[0] + + if existToPort == newToPort { + isExist = true + break + } + } + } + + return isExist +} + func mergeIngressPolicies(existPolicy types.KnoxNetworkPolicy, policies []types.KnoxNetworkPolicy) (types.KnoxNetworkPolicy, bool) { mergedPolicy := existPolicy updated := false @@ -1598,13 +1630,18 @@ func mergeIngressPolicies(existPolicy types.KnoxNetworkPolicy, policies []types. } } } + } else if len(newIngress.FromCIDRs) > 0 && len(newIngress.ToPorts) > 0 { + newToPort := newIngress.ToPorts[0] + ingressMatched = checkIfIngressEgressPortExist("INGRESS", newToPort, mergedPolicy) } + if !ingressMatched { mergedPolicy.Spec.Ingress = append(mergedPolicy.Spec.Ingress, newIngress) updated = true } } } + return mergedPolicy, updated } @@ -1668,7 +1705,11 @@ func mergeEgressPolicies(existPolicy types.KnoxNetworkPolicy, policies []types.K } } } + } else if len(newEgress.ToCIDRs) > 0 && len(newEgress.ToPorts) > 0 { + newToPort := newEgress.ToPorts[0] + egressMatched = checkIfIngressEgressPortExist("EGRESS", newToPort, mergedPolicy) } + if !egressMatched { mergedPolicy.Spec.Egress = append(mergedPolicy.Spec.Egress, newEgress) updated = true @@ -1726,6 +1767,44 @@ func mergeHttpRules(existRule types.L47Rule, newRule types.L47Rule) (bool, bool, return false, false, nil } +func populateIngressEgressPolicyFromKnoxNetLog(log *types.KnoxNetworkLog, pods []types.Pod) types.KnoxNetworkPolicy { + iePolicy := types.KnoxNetworkPolicy{} + var cidrs []string + cidrs = append(cidrs, "0.0.0.0/32") + + specVal := types.SpecCIDR{ + CIDRs: cidrs, + } + + portVal := types.SpecPort{ + Port: strconv.Itoa(log.DstPort), + Protocol: libs.GetProtocol(log.Protocol), + } + + if log.Direction == "EGRESS" { + iePolicy = buildNewKnoxEgressPolicy() + egress := types.Egress{} + + egress.ToPorts = append(egress.ToPorts, portVal) + egress.ToCIDRs = append(egress.ToCIDRs, specVal) + + iePolicy.Spec.Egress = append(iePolicy.Spec.Egress, egress) + + } else if log.Direction == "INGRESS" { + iePolicy = buildNewKnoxIngressPolicy() + ingress := types.Ingress{} + + ingress.ToPorts = append(ingress.ToPorts, portVal) + ingress.FromCIDRs = append(ingress.FromCIDRs, specVal) + + iePolicy.Spec.Ingress = append(iePolicy.Spec.Ingress, ingress) + } + + iePolicy.Spec.Selector.MatchLabels = getEndpointMatchLabels(log.SrcPodName, pods) + + return iePolicy +} + func convertKnoxNetworkLogToKnoxNetworkPolicy(log *types.KnoxNetworkLog, pods []types.Pod) (_, _ *types.KnoxNetworkPolicy) { var ingressPolicy, egressPolicy *types.KnoxNetworkPolicy = nil, nil @@ -1858,6 +1937,13 @@ func convertKnoxNetworkLogToKnoxNetworkPolicy(log *types.KnoxNetworkLog, pods [] ePolicy.Metadata["namespace"] = log.SrcNamespace egressPolicy = &ePolicy } + } else if log.DstPodName == "" && len(log.DstReservedLabels) == 0 { + iePolicy := populateIngressEgressPolicyFromKnoxNetLog(log, pods) + if log.Direction == "EGRESS" { + egressPolicy = &iePolicy + } else if log.Direction == "INGRESS" { + ingressPolicy = &iePolicy + } } if !isValidPolicy(ingressPolicy) { @@ -2134,47 +2220,79 @@ func PopulateNetworkPoliciesFromNetworkLogs(networkLogs []types.KnoxNetworkLog) func writeNetworkPoliciesYamlToDB(policies []types.KnoxNetworkPolicy) { clusters := []string{} + res := []types.PolicyYaml{} for _, pol := range policies { clusters = append(clusters, pol.Metadata["cluster_name"]) } - // convert knoxPolicy to CiliumPolicy - ciliumPolicies := plugin.ConvertKnoxPoliciesToCiliumPolicies(policies) + if cfg.CurrentCfg.ConfigNetPolicy.NetworkLogFrom == "kubearmor" { + k8sNetPolicies := plugin.ConvertKnoxNetPolicyToK8sNetworkPolicy("", "", policies) - res := []types.PolicyYaml{} + for i, np := range k8sNetPolicies { + np.ClusterName = "" + jsonBytes, err := json.Marshal(np) + if err != nil { + log.Error().Msg(err.Error()) + continue + } + yamlBytes, err := yaml.JSONToYAML(jsonBytes) + if err != nil { + log.Error().Msg(err.Error()) + continue + } - for i, ciliumPolicy := range ciliumPolicies { - jsonBytes, err := json.Marshal(ciliumPolicy) - if err != nil { - log.Error().Msg(err.Error()) - continue - } - yamlBytes, err := yaml.JSONToYAML(jsonBytes) - if err != nil { - log.Error().Msg(err.Error()) - continue - } + policyYaml := types.PolicyYaml{ + Type: types.PolicyTypeNetwork, + Kind: np.Kind, + Name: np.Name, + Namespace: np.Namespace, + Cluster: clusters[i], + Labels: np.Labels, + Yaml: yamlBytes, + } + res = append(res, policyYaml) - var labels types.LabelMap - if ciliumPolicy.Kind == cu.ResourceTypeCiliumNetworkPolicy { - labels = ciliumPolicy.Spec.EndpointSelector.MatchLabels - } else { - labels = ciliumPolicy.Spec.NodeSelector.MatchLabels + PolicyStore.Publish(&policyYaml) } - policyYaml := types.PolicyYaml{ - Type: types.PolicyTypeNetwork, - Kind: ciliumPolicy.Kind, - Name: ciliumPolicy.Metadata["name"], - Namespace: ciliumPolicy.Metadata["namespace"], - Cluster: clusters[i], - Labels: labels, - Yaml: yamlBytes, - } - res = append(res, policyYaml) + } else { - PolicyStore.Publish(&policyYaml) + // convert knoxPolicy to CiliumPolicy + ciliumPolicies := plugin.ConvertKnoxPoliciesToCiliumPolicies(policies) + + for i, ciliumPolicy := range ciliumPolicies { + jsonBytes, err := json.Marshal(ciliumPolicy) + if err != nil { + log.Error().Msg(err.Error()) + continue + } + yamlBytes, err := yaml.JSONToYAML(jsonBytes) + if err != nil { + log.Error().Msg(err.Error()) + continue + } + + var labels types.LabelMap + if ciliumPolicy.Kind == cu.ResourceTypeCiliumNetworkPolicy { + labels = ciliumPolicy.Spec.EndpointSelector.MatchLabels + } else { + labels = ciliumPolicy.Spec.NodeSelector.MatchLabels + } + + policyYaml := types.PolicyYaml{ + Type: types.PolicyTypeNetwork, + Kind: ciliumPolicy.Kind, + Name: ciliumPolicy.Metadata["name"], + Namespace: ciliumPolicy.Metadata["namespace"], + Cluster: clusters[i], + Labels: labels, + Yaml: yamlBytes, + } + res = append(res, policyYaml) + + PolicyStore.Publish(&policyYaml) + } } if err := libs.UpdateOrInsertPolicyYamls(CfgDB, res); err != nil { diff --git a/src/plugin/k8sNetwork.go b/src/plugin/k8sNetwork.go index ffb629e6..c7cd00d7 100644 --- a/src/plugin/k8sNetwork.go +++ b/src/plugin/k8sNetwork.go @@ -3,8 +3,6 @@ package plugin import ( "strconv" - "github.com/accuknox/auto-policy-discovery/src/config" - "github.com/accuknox/auto-policy-discovery/src/libs" "github.com/accuknox/auto-policy-discovery/src/types" v1 "k8s.io/api/core/v1" nv1 "k8s.io/api/networking/v1" @@ -12,9 +10,8 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) -func ConvertKnoxNetPolicyToK8sNetworkPolicy(clustername, namespace string) []nv1.NetworkPolicy { +func ConvertKnoxNetPolicyToK8sNetworkPolicy(clustername, namespace string, knoxNetPolicies []types.KnoxNetworkPolicy) []nv1.NetworkPolicy { - knoxNetPolicies := libs.GetNetworkPolicies(config.CurrentCfg.ConfigDB, clustername, namespace, "latest", "", "") log.Info().Msgf("No. of knox network policies - %d", len(knoxNetPolicies)) if len(knoxNetPolicies) <= 0 { @@ -31,11 +28,13 @@ func ConvertKnoxNetPolicyToK8sNetworkPolicy(clustername, namespace string) []nv1 k8NetPol.Name = knp.Metadata["name"] k8NetPol.Namespace = knp.Metadata["namespace"] k8NetPol.ClusterName = knp.Metadata["cluster_name"] + k8NetPol.Labels = knp.Spec.Selector.MatchLabels if len(knp.Spec.Egress) > 0 { - for _, eg := range knp.Spec.Egress { var egressRule nv1.NetworkPolicyEgressRule + port := nv1.NetworkPolicyPort{} + to := nv1.NetworkPolicyPeer{} var protocol v1.Protocol if eg.ToPorts[0].Protocol == string(v1.ProtocolTCP) { @@ -43,24 +42,35 @@ func ConvertKnoxNetPolicyToK8sNetworkPolicy(clustername, namespace string) []nv1 } else if eg.ToPorts[0].Protocol == string(v1.ProtocolUDP) { protocol = v1.ProtocolUDP } + portVal, _ := strconv.ParseInt(eg.ToPorts[0].Port, 10, 32) - port := nv1.NetworkPolicyPort{ - Port: &intstr.IntOrString{ - Type: intstr.Int, - IntVal: int32(portVal), - }, - Protocol: &protocol, + if portVal != 0 { + port = nv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + Type: intstr.Int, + IntVal: int32(portVal), + }, + Protocol: &protocol, + } + } else { + port = nv1.NetworkPolicyPort{ + Protocol: &protocol, + } } - to := nv1.NetworkPolicyPeer{ - PodSelector: &metav1.LabelSelector{ - MatchLabels: eg.MatchLabels, - }, + if len(eg.MatchLabels) > 0 { + to = nv1.NetworkPolicyPeer{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: eg.MatchLabels, + }, + } + egressRule.To = append(egressRule.To, to) + } else { + egressRule.To = nil } egressRule.Ports = append(egressRule.Ports, port) - egressRule.To = append(egressRule.To, to) k8NetPol.Spec.Egress = append(k8NetPol.Spec.Egress, egressRule) } @@ -71,37 +81,51 @@ func ConvertKnoxNetPolicyToK8sNetworkPolicy(clustername, namespace string) []nv1 if len(knp.Spec.Ingress) > 0 { for _, ing := range knp.Spec.Ingress { var ingressRule nv1.NetworkPolicyIngressRule + port := nv1.NetworkPolicyPort{} var protocol v1.Protocol + from := nv1.NetworkPolicyPeer{} if ing.ToPorts[0].Protocol == string(v1.ProtocolTCP) { protocol = v1.ProtocolTCP } else if ing.ToPorts[0].Protocol == string(v1.ProtocolUDP) { protocol = v1.ProtocolUDP } + portVal, _ := strconv.ParseInt(ing.ToPorts[0].Port, 10, 32) - port := nv1.NetworkPolicyPort{ - Port: &intstr.IntOrString{ - Type: intstr.Int, - IntVal: int32(portVal), - }, - Protocol: &protocol, + if portVal != 0 { + port = nv1.NetworkPolicyPort{ + Port: &intstr.IntOrString{ + Type: intstr.Int, + IntVal: int32(portVal), + }, + Protocol: &protocol, + } + } else { + port = nv1.NetworkPolicyPort{ + Protocol: &protocol, + } } - from := nv1.NetworkPolicyPeer{ - PodSelector: &metav1.LabelSelector{ - MatchLabels: ing.MatchLabels, - }, + if len(ing.MatchLabels) > 0 { + from = nv1.NetworkPolicyPeer{ + PodSelector: &metav1.LabelSelector{ + MatchLabels: ing.MatchLabels, + }, + } + ingressRule.From = append(ingressRule.From, from) + } else { + ingressRule.From = nil } ingressRule.Ports = append(ingressRule.Ports, port) - ingressRule.From = append(ingressRule.From, from) k8NetPol.Spec.Ingress = append(k8NetPol.Spec.Ingress, ingressRule) } k8NetPol.Spec.PolicyTypes = append(k8NetPol.Spec.PolicyTypes, nv1.PolicyType(nv1.PolicyTypeIngress)) } + k8NetPol.Spec.PodSelector.MatchLabels = k8NetPol.Labels res = append(res, k8NetPol) } diff --git a/src/plugin/kubearmor.go b/src/plugin/kubearmor.go index 74a54e19..4273e26a 100644 --- a/src/plugin/kubearmor.go +++ b/src/plugin/kubearmor.go @@ -422,7 +422,7 @@ func StartKubeArmorRelay(StopChan chan struct{}, cfg types.ConfigKubeArmorRelay) continue } - if !strings.HasPrefix(res.Resource, "/") { + if res.Operation != "Network" && !strings.HasPrefix(res.Resource, "/") { log.Warn().Msgf("Relative path found: %v", res) continue } @@ -436,7 +436,7 @@ func StartKubeArmorRelay(StopChan chan struct{}, cfg types.ConfigKubeArmorRelay) } if config.CurrentCfg.ConfigNetPolicy.NetworkLogFrom == "kubearmor" { - if res.Operation == "Network" && strings.Contains(res.Data, "tcp_") { + if res.Operation == "Network" { KubeArmorNetworkLogs = append(KubeArmorNetworkLogs, res) } } @@ -490,7 +490,7 @@ func StartKubeArmorRelay(StopChan chan struct{}, cfg types.ConfigKubeArmorRelay) continue } - if !strings.HasPrefix(res.Resource, "/") { + if res.Operation != "Network" && !strings.HasPrefix(res.Resource, "/") { log.Warn().Msgf("Relative path found: %v", res) continue } @@ -504,8 +504,8 @@ func StartKubeArmorRelay(StopChan chan struct{}, cfg types.ConfigKubeArmorRelay) } if config.CurrentCfg.ConfigNetPolicy.NetworkLogFrom == "kubearmor" { - if kubearmorLog.Operation == "Network" && (strings.Contains(kubearmorLog.Data, "tcp_") || - strings.Contains(kubearmorLog.Resource, "UDP")) { + + if kubearmorLog.Operation == "Network" { KubeArmorNetworkLogs = append(KubeArmorNetworkLogs, &kubearmorLog) } } @@ -585,7 +585,7 @@ func ConvertKubeArmorNetLogToKnoxNetLog(kaNwLogs []*pb.Log) []types.KnoxNetworkL } } - if ip == "127.0.0.1" { + if net.ParseIP(ip).IsLoopback() { // ignore adding policies with pod IP pointing to localhost continue } @@ -600,8 +600,23 @@ func ConvertKubeArmorNetLogToKnoxNetLog(kaNwLogs []*pb.Log) []types.KnoxNetworkL locKnoxLog.DstIP = ip locKnoxLog.DstPort, _ = strconv.Atoi(port) locKnoxLog.SynFlag = true - } else { + } else if strings.Contains(kalog.Data, "SYS_BIND") { + var port string + locKnoxLog.Protocol = libs.IPProtocolUDP + + resSlice := strings.Split(kalog.Resource, " ") + for _, v := range resSlice { + if strings.Contains(v, "sin_port") { + port = strings.Split(v, "=")[1] + } + } + //locKnoxLog.DstIP = "0.0.0.0" + locKnoxLog.DstPort, _ = strconv.Atoi(port) + locKnoxLog.Direction = "INGRESS" + } else if strings.Contains(kalog.Data, "SYS_SOCKET") && strings.Contains(kalog.Resource, "SOCK_DGRAM") { locKnoxLog.Protocol = libs.IPProtocolUDP + //locKnoxLog.DstIP = "0.0.0.0" + locKnoxLog.Direction = "EGRESS" } if kalog.Result != "Passed" {