diff --git a/actionners/actionners.go b/actionners/actionners.go index 4b166be1..16eb0b78 100644 --- a/actionners/actionners.go +++ b/actionners/actionners.go @@ -3,14 +3,16 @@ package actionners import ( "fmt" + calicoNetworkpolicy "github.com/Falco-Talon/falco-talon/actionners/calico/networkpolicy" k8sDelete "github.com/Falco-Talon/falco-talon/actionners/kubernetes/delete" - "github.com/Falco-Talon/falco-talon/actionners/kubernetes/exec" + k8sExec "github.com/Falco-Talon/falco-talon/actionners/kubernetes/exec" k8sLabelize "github.com/Falco-Talon/falco-talon/actionners/kubernetes/labelize" k8sLog "github.com/Falco-Talon/falco-talon/actionners/kubernetes/log" - "github.com/Falco-Talon/falco-talon/actionners/kubernetes/networkpolicy" - "github.com/Falco-Talon/falco-talon/actionners/kubernetes/script" + k8sNetworkpolicy "github.com/Falco-Talon/falco-talon/actionners/kubernetes/networkpolicy" + k8sScript "github.com/Falco-Talon/falco-talon/actionners/kubernetes/script" k8sTerminate "github.com/Falco-Talon/falco-talon/actionners/kubernetes/terminate" "github.com/Falco-Talon/falco-talon/configuration" + calico "github.com/Falco-Talon/falco-talon/internal/calico/client" "github.com/Falco-Talon/falco-talon/internal/events" k8sChecks "github.com/Falco-Talon/falco-talon/internal/kubernetes/checks" k8s "github.com/Falco-Talon/falco-talon/internal/kubernetes/client" @@ -79,8 +81,8 @@ func GetDefaultActionners() *Actionners { Checks: []checkActionner{ k8sChecks.CheckPodExist, }, - CheckParameters: networkpolicy.CheckParameters, - Action: networkpolicy.Action, + CheckParameters: k8sNetworkpolicy.CheckParameters, + Action: k8sNetworkpolicy.Action, }, &Actionner{ Category: "kubernetes", @@ -90,8 +92,8 @@ func GetDefaultActionners() *Actionners { Checks: []checkActionner{ k8sChecks.CheckPodExist, }, - CheckParameters: exec.CheckParameters, - Action: exec.Action, + CheckParameters: k8sExec.CheckParameters, + Action: k8sExec.Action, }, &Actionner{ Category: "kubernetes", @@ -101,8 +103,8 @@ func GetDefaultActionners() *Actionners { Checks: []checkActionner{ k8sChecks.CheckPodExist, }, - CheckParameters: script.CheckParameters, - Action: script.Action, + CheckParameters: k8sScript.CheckParameters, + Action: k8sScript.Action, }, &Actionner{ Category: "kubernetes", @@ -121,11 +123,24 @@ func GetDefaultActionners() *Actionners { DefaultContinue: false, Init: k8s.Init, Checks: []checkActionner{ - k8sChecks.CheckTargetExist, + k8sChecks.CheckPodExist, }, CheckParameters: nil, Action: k8sDelete.Action, }, + &Actionner{ + Category: "calico", + Name: "networkpolicy", + DefaultContinue: false, + Init: calico.Init, + Checks: []checkActionner{ + k8sChecks.CheckPodExist, + k8sChecks.CheckRemoteIP, + k8sChecks.CheckRemotePort, + }, + CheckParameters: nil, + Action: calicoNetworkpolicy.Action, + }, ) } diff --git a/actionners/calico/networkpolicy/networkpolicy.go b/actionners/calico/networkpolicy/networkpolicy.go new file mode 100644 index 00000000..70511975 --- /dev/null +++ b/actionners/calico/networkpolicy/networkpolicy.go @@ -0,0 +1,183 @@ +package networkpolicy + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + "strings" + + networkingv3 "github.com/projectcalico/api/pkg/apis/projectcalico/v3" + "github.com/projectcalico/api/pkg/lib/numorstring" + errorsv1 "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + calico "github.com/Falco-Talon/falco-talon/internal/calico/client" + + "github.com/Falco-Talon/falco-talon/internal/events" + kubernetes "github.com/Falco-Talon/falco-talon/internal/kubernetes/client" + "github.com/Falco-Talon/falco-talon/internal/rules" + "github.com/Falco-Talon/falco-talon/utils" +) + +func Action(_ *rules.Action, event *events.Event) (utils.LogLine, error) { + podName := event.GetPodName() + namespace := event.GetNamespaceName() + + objects := map[string]string{ + "pod": podName, + "namespace": namespace, + } + k8sClient := kubernetes.GetClient() + calicoClient := calico.GetClient() + + pod, err := k8sClient.GetPod(podName, namespace) + if err != nil { + return utils.LogLine{ + Objects: objects, + Error: err.Error(), + Status: "failure", + }, + err + } + + var owner string + labels := make(map[string]string) + + if len(pod.OwnerReferences) != 0 { + switch pod.OwnerReferences[0].Kind { + case "DaemonSet": + u, err2 := k8sClient.GetDaemonsetFromPod(pod) + if err2 != nil { + return utils.LogLine{ + Objects: objects, + Error: err2.Error(), + Status: "failure", + }, + err2 + } + owner = u.ObjectMeta.Name + labels = u.Spec.Selector.MatchLabels + case "StatefulSet": + u, err2 := k8sClient.GetStatefulsetFromPod(pod) + if err2 != nil { + return utils.LogLine{ + Objects: objects, + Error: err2.Error(), + Status: "failure", + }, + err2 + } + owner = u.ObjectMeta.Name + labels = u.Spec.Selector.MatchLabels + case "ReplicaSet": + u, err2 := k8sClient.GetReplicasetFromPod(pod) + if err2 != nil { + return utils.LogLine{ + Objects: objects, + Error: err2.Error(), + Status: "failure", + }, + err2 + } + owner = u.ObjectMeta.Name + labels = u.Spec.Selector.MatchLabels + } + } else { + owner = pod.ObjectMeta.Name + labels = pod.ObjectMeta.Labels + } + + if owner == "" || len(labels) == 0 { + err3 := fmt.Errorf("can't find the owner and/or labels for the pod '%v' in the namespace '%v'", podName, namespace) + return utils.LogLine{ + Objects: objects, + Error: err3.Error(), + Status: "failure", + }, + err3 + } + + delete(labels, "pod-template-hash") + + payload := networkingv3.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: owner, + Namespace: namespace, + Labels: labels, + }, + Spec: networkingv3.NetworkPolicySpec{ + Types: []networkingv3.PolicyType{networkingv3.PolicyTypeEgress}, + }, + } + + var selector string + for i, j := range labels { + selector += fmt.Sprintf(`%v == "%v" &&`, i, j) + } + + payload.Spec.Selector = strings.TrimSuffix(selector, " &&") + + r, err := createEgressRule(event) + if err != nil { + return utils.LogLine{ + Objects: objects, + Error: err.Error(), + Status: "failure", + }, + err + } + + if r != nil { + payload.Spec.Egress = []networkingv3.Rule{*r} + } + + j, _ := json.Marshal(payload) + fmt.Println(string(j)) + + var output string + _, err = calicoClient.ProjectcalicoV3().NetworkPolicies(namespace).List(context.Background(), metav1.ListOptions{}) + if errorsv1.IsNotFound(err) { + _, err = calicoClient.ProjectcalicoV3().NetworkPolicies(namespace).Create(context.Background(), &payload, metav1.CreateOptions{}) + output = fmt.Sprintf("the networkpolicy '%v' in the namespace '%v' has been created", owner, namespace) + } else { + _, err = calicoClient.ProjectcalicoV3().NetworkPolicies(namespace).Update(context.Background(), &payload, metav1.UpdateOptions{}) + output = fmt.Sprintf("the networkpolicy '%v' in the namespace '%v' has been updated", owner, namespace) + } + if err != nil { + return utils.LogLine{ + Objects: objects, + Error: err.Error(), + Status: "failure", + }, + err + } + objects["NetworkPolicy"] = owner + return utils.LogLine{ + Objects: objects, + Output: output, + Status: "success", + }, + nil +} + +func createEgressRule(event *events.Event) (*networkingv3.Rule, error) { + port, err := strconv.ParseUint(event.GetRemotePort(), 0, 16) + if err != nil { + return nil, err + } + r := networkingv3.Rule{ + Action: "Deny", + Destination: networkingv3.EntityRule{ + Nets: []string{event.GetRemoteIP()}, + Ports: []numorstring.Port{ + { + MinPort: uint16(port), + MaxPort: uint16(port), + }, + }, + }, + } + + return &r, nil +} diff --git a/actionners/kubernetes/networkpolicy/networkpolicy.go b/actionners/kubernetes/networkpolicy/networkpolicy.go index d4de41f0..8c568679 100644 --- a/actionners/kubernetes/networkpolicy/networkpolicy.go +++ b/actionners/kubernetes/networkpolicy/networkpolicy.go @@ -5,7 +5,6 @@ import ( "fmt" "net" - v1 "k8s.io/api/apps/v1" networkingv1 "k8s.io/api/networking/v1" errorsv1 "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -36,125 +35,61 @@ func Action(action *rules.Action, event *events.Event) (utils.LogLine, error) { err } - labels := make(map[string]string) var owner string + labels := make(map[string]string) if len(pod.OwnerReferences) != 0 { switch pod.OwnerReferences[0].Kind { case "DaemonSet": - u, errG := client.GetDaemonsetFromPod(pod) - if errG != nil { - return utils.LogLine{ - Objects: objects, - Error: errG.Error(), - Status: "failure", - }, - errG - } - if u == nil { + u, err2 := client.GetDaemonsetFromPod(pod) + if err2 != nil { return utils.LogLine{ Objects: objects, - Error: fmt.Sprintf("can't find the daemonset for the pod %v in namespace %v", podName, namespace), + Error: err2.Error(), Status: "failure", }, - fmt.Errorf("can't find the daemonset for the pod %v in namespace %v", podName, namespace) + err2 } owner = u.ObjectMeta.Name labels = u.Spec.Selector.MatchLabels - if owner == "" || len(labels) == 0 { - return utils.LogLine{ - Objects: objects, - Error: fmt.Sprintf("can't find the owner and/or labels for the pod %v in namespace %v", podName, namespace), - Status: "failure", - }, - fmt.Errorf("can't find the owner and/or labels for the pod %v in namespace %v", podName, namespace) - } case "StatefulSet": - u, errG := client.GetStatefulsetFromPod(pod) - if errG != nil { - return utils.LogLine{ - Objects: objects, - Error: errG.Error(), - Status: "failure", - }, - errG - } - if u == nil { + u, err2 := client.GetStatefulsetFromPod(pod) + if err2 != nil { return utils.LogLine{ Objects: objects, - Error: fmt.Sprintf("can't find the statefulset for the pod %v in namespace %v", podName, namespace), + Error: err2.Error(), Status: "failure", }, - fmt.Errorf("can't find the statefulset for the pod %v in namespace %v", podName, namespace) + err2 } owner = u.ObjectMeta.Name labels = u.Spec.Selector.MatchLabels - if owner == "" || len(labels) == 0 { - return utils.LogLine{ - Objects: objects, - Error: fmt.Sprintf("can't find the owner and/or labels for the pod %v in namespace %v", podName, namespace), - Status: "failure", - }, - fmt.Errorf("can't find the owner and/or labels for the pod %v in namespace %v", podName, namespace) - } case "ReplicaSet": - u, errG := client.GetReplicasetFromPod(pod) - if errG != nil { - return utils.LogLine{ - Objects: objects, - Error: errG.Error(), - Status: "failure", - }, - errG - } - if u == nil { - return utils.LogLine{ - Objects: objects, - Error: fmt.Sprintf("can't find the replicaset for the pod %v in namespace %v", podName, namespace), - Status: "failure", - }, - fmt.Errorf("can't find the replicaset for the pod %v in namespace %v", podName, namespace) - } - var v *v1.Deployment - v, errG = client.Clientset.AppsV1().Deployments(namespace).Get(context.Background(), u.OwnerReferences[0].Name, metav1.GetOptions{}) - if errG != nil { - return utils.LogLine{ - Objects: objects, - Error: errG.Error(), - Status: "failure", - }, - errG - } - if v == nil { - return utils.LogLine{ - Objects: objects, - Error: fmt.Sprintf("can't find the deployment for the pod %v in namespace %v", podName, namespace), - Status: "failure", - }, - fmt.Errorf("can't find the deployment for the pod %v in namespace %v", podName, namespace) - } - owner = v.ObjectMeta.Name - labels = v.Spec.Selector.MatchLabels - if owner == "" || len(labels) == 0 { + u, err2 := client.GetReplicasetFromPod(pod) + if err2 != nil { return utils.LogLine{ Objects: objects, - Error: fmt.Sprintf("can't find the owner and/or labels for the pod %v in namespace %v", podName, namespace), + Error: err2.Error(), Status: "failure", }, - fmt.Errorf("can't find the owner and/or labels for the pod %v in namespace %v", podName, namespace) + err2 } + owner = u.ObjectMeta.Name + labels = u.Spec.Selector.MatchLabels } } else { owner = pod.ObjectMeta.Name labels = pod.ObjectMeta.Labels - if owner == "" || len(labels) == 0 { - return utils.LogLine{ - Objects: objects, - Error: fmt.Sprintf("can't find the owner and/or labels for the pod %v in namespace %v", podName, namespace), - Status: "failure", - }, - fmt.Errorf("can't find the owner and/or labels for the pod %v in namespace %v", podName, namespace) - } + } + + if owner == "" || len(labels) == 0 { + err3 := fmt.Errorf("can't find the owner and/or labels for the pod '%v' in namespace '%v'", podName, namespace) + return utils.LogLine{ + Objects: objects, + Error: err3.Error(), + Status: "failure", + }, + err3 } delete(labels, "pod-template-hash") diff --git a/go.mod b/go.mod index 9ecd8b31..63f8590d 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/google/uuid v1.6.0 github.com/jinzhu/copier v0.4.0 github.com/magefile/mage v1.15.0 + github.com/projectcalico/api v0.0.0-20231218190037-9183ab93f33e github.com/prometheus/client_golang v1.18.0 github.com/rs/zerolog v1.32.0 github.com/spf13/cobra v1.8.0 diff --git a/go.sum b/go.sum index 5b87baba..91170f3b 100644 --- a/go.sum +++ b/go.sum @@ -102,6 +102,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= @@ -112,6 +116,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/projectcalico/api v0.0.0-20231218190037-9183ab93f33e h1:y+vvu0zmrVjJ3wTVbF1AczfFlqv3fu3qvvFqPlTd+DY= +github.com/projectcalico/api v0.0.0-20231218190037-9183ab93f33e/go.mod h1:Ld33cK0XfntgQU6YdMZ/Hb0JbWTD2NvBR8L4K8MH1ME= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= @@ -240,6 +246,8 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/calico/client/client.go b/internal/calico/client/client.go new file mode 100644 index 00000000..165d51d2 --- /dev/null +++ b/internal/calico/client/client.go @@ -0,0 +1,47 @@ +package kubernetes + +import ( + calico "github.com/projectcalico/api/pkg/client/clientset_generated/clientset" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + + "github.com/Falco-Talon/falco-talon/configuration" + kubernetes "github.com/Falco-Talon/falco-talon/internal/kubernetes/client" +) + +type Client struct { + *calico.Clientset +} + +var client *Client + +func Init() error { + // the calico category requires also a k8s client + if err := kubernetes.Init(); err != nil { + return err + } + + client = new(Client) + config := configuration.GetConfiguration() + var err error + var restConfig *rest.Config + if config.KubeConfig != "" { + restConfig, err = clientcmd.BuildConfigFromFlags("", config.KubeConfig) + } else { + restConfig, err = rest.InClusterConfig() + } + if err != nil { + return err + } + + // creates the clientset + client.Clientset, err = calico.NewForConfig(restConfig) + if err != nil { + return err + } + return nil +} + +func GetClient() *Client { + return client +} diff --git a/internal/events/events.go b/internal/events/events.go index 9ba513a0..ec67f3ad 100644 --- a/internal/events/events.go +++ b/internal/events/events.go @@ -75,3 +75,23 @@ func (event *Event) GetTargetResource() string { } return "" } + +func (event *Event) GetRemoteIP() string { + if i := event.OutputFields["fd.rip"]; i != nil { + return i.(string) + } + if i := event.OutputFields["fd.sip"]; i != nil { + return i.(string) + } + return "" +} + +func (event *Event) GetRemotePort() string { + if i := event.OutputFields["fd.rport"]; i != nil { + return i.(string) + } + if i := event.OutputFields["fd.sport"]; i != nil { + return i.(string) + } + return "" +} diff --git a/internal/kubernetes/checks/checks.go b/internal/kubernetes/checks/checks.go index 358ce031..ecc0db13 100644 --- a/internal/kubernetes/checks/checks.go +++ b/internal/kubernetes/checks/checks.go @@ -2,11 +2,16 @@ package checks import ( "errors" + "net" + "strconv" + "strings" "github.com/Falco-Talon/falco-talon/internal/events" kubernetes "github.com/Falco-Talon/falco-talon/internal/kubernetes/client" ) +const na string = "" + func CheckPodName(event *events.Event) error { pod := event.GetPodName() if pod == "" { @@ -65,6 +70,23 @@ func CheckRemoteIP(event *events.Event) error { event.OutputFields["fd.rip"] == nil { return errors.New("missing IP field(s) (fd.sip or fd.rip)") } + if event.OutputFields["fd.sip"] != nil { + if event.OutputFields["fd.sip"].(string) == na { + return errors.New(" value for fd.sip") + } + if net.ParseIP(event.OutputFields["fd.sip"].(string)) == nil { + return errors.New("wrong value for fd.sip") + } + } + if event.OutputFields["fd.rip"] != nil { + if strings.ToLower(event.OutputFields["fd.rip"].(string)) == na { + return errors.New(" value for fd.rip") + } + if net.ParseIP(event.OutputFields["fd.rip"].(string)) == nil { + return errors.New("wrong value for fd.rip") + } + } + return nil } @@ -73,6 +95,17 @@ func CheckRemotePort(event *events.Event) error { event.OutputFields["fd.rport"] == nil { return errors.New("missing Port field(s) (fd.sport or fd.port)") } + if event.OutputFields["fd.sport"] != nil { + if _, err := strconv.ParseUint(event.GetRemotePort(), 0, 16); err != nil { + return errors.New("wrong value for fd.sport") + } + } + if event.OutputFields["fd.rport"] != nil { + if _, err := strconv.ParseUint(event.GetRemotePort(), 0, 16); err != nil { + return errors.New("wrong value for fd.rport") + } + } + return nil } diff --git a/internal/kubernetes/client/client.go b/internal/kubernetes/client/client.go index 6247bbb2..c75a2388 100644 --- a/internal/kubernetes/client/client.go +++ b/internal/kubernetes/client/client.go @@ -23,7 +23,7 @@ type Client struct { var client *Client -var Init = func() error { +func Init() error { client = new(Client) config := configuration.GetConfiguration() var err error @@ -64,35 +64,87 @@ func GetContainers(pod *corev1.Pod) []string { return c } -func (client Client) GetDaemonsetFromPod(pod *corev1.Pod) (*appsv1.DaemonSet, error) { - d, err := client.Clientset.AppsV1().DaemonSets(pod.ObjectMeta.Namespace).Get(context.Background(), pod.OwnerReferences[0].Name, metav1.GetOptions{}) +func (client Client) GetDeployment(name, namespace string) (*appsv1.Deployment, error) { + p, err := client.Clientset.AppsV1().Deployments(namespace).Get(context.Background(), name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("the deployment '%v' in the namespace '%v' doesn't exist", name, namespace) + } + return p, nil +} + +func (client Client) GetDaemonSet(name, namespace string) (*appsv1.DaemonSet, error) { + p, err := client.Clientset.AppsV1().DaemonSets(namespace).Get(context.Background(), name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("the daemonset '%v' in the namespace '%v' doesn't exist", name, namespace) + } + return p, nil +} + +func (client Client) GetStatefulSet(name, namespace string) (*appsv1.StatefulSet, error) { + p, err := client.Clientset.AppsV1().StatefulSets(namespace).Get(context.Background(), name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("the statefulset '%v' in the namespace '%v' doesn't exist", name, namespace) + } + return p, nil +} + +func (client Client) GetReplicaSet(name, namespace string) (*appsv1.ReplicaSet, error) { + p, err := client.Clientset.AppsV1().ReplicaSets(namespace).Get(context.Background(), name, metav1.GetOptions{}) + if err != nil { + return nil, fmt.Errorf("the replicaset '%v' in the namespace '%v' doesn't exist", name, namespace) + } + return p, nil +} + +func (client Client) GetDeploymentFromPod(pod *corev1.Pod) (*appsv1.Deployment, error) { + podName := pod.OwnerReferences[0].Name + namespace := pod.ObjectMeta.Namespace + r, err := client.GetDeployment(podName, namespace) if err != nil { return nil, err } - return d, nil + if r == nil { + return nil, fmt.Errorf("can't find the deployment for the pod'%v' in namespace '%v'", pod, namespace) + } + return r, nil } -func (client Client) GetStatefulsetFromPod(pod *corev1.Pod) (*appsv1.StatefulSet, error) { - s, err := client.Clientset.AppsV1().StatefulSets(pod.ObjectMeta.Namespace).Get(context.Background(), pod.OwnerReferences[0].Name, metav1.GetOptions{}) +func (client Client) GetDaemonsetFromPod(pod *corev1.Pod) (*appsv1.DaemonSet, error) { + podName := pod.OwnerReferences[0].Name + namespace := pod.ObjectMeta.Namespace + r, err := client.GetDaemonSet(podName, namespace) if err != nil { return nil, err } - return s, nil + if r == nil { + return nil, fmt.Errorf("can't find the daemonset for the pod'%v' in namespace '%v'", pod, namespace) + } + return r, nil } -func (client Client) GetReplicasetFromPod(pod *corev1.Pod) (*appsv1.ReplicaSet, error) { - r, err := client.Clientset.AppsV1().ReplicaSets(pod.ObjectMeta.Namespace).Get(context.Background(), pod.OwnerReferences[0].Name, metav1.GetOptions{}) +func (client Client) GetStatefulsetFromPod(pod *corev1.Pod) (*appsv1.StatefulSet, error) { + podName := pod.OwnerReferences[0].Name + namespace := pod.ObjectMeta.Namespace + r, err := client.GetStatefulSet(podName, namespace) if err != nil { return nil, err } + if r == nil { + return nil, fmt.Errorf("can't find the statefulset for the pod'%v' in namespace '%v'", pod, namespace) + } return r, nil } -func (client Client) GetDeloymentFromPod(pod *corev1.Pod) (*appsv1.ReplicaSet, error) { - r, err := client.Clientset.AppsV1().ReplicaSets(pod.ObjectMeta.Namespace).Get(context.Background(), pod.OwnerReferences[0].Name, metav1.GetOptions{}) +func (client Client) GetReplicasetFromPod(pod *corev1.Pod) (*appsv1.ReplicaSet, error) { + podName := pod.OwnerReferences[0].Name + namespace := pod.ObjectMeta.Namespace + r, err := client.GetReplicaSet(podName, namespace) if err != nil { return nil, err } + if r == nil { + return nil, fmt.Errorf("can't find the replicaset for the pod'%v' in namespace '%v'", pod, namespace) + } return r, nil } @@ -139,38 +191,6 @@ func (client Client) GetSecret(name, namespace string) (*corev1.Secret, error) { return p, nil } -func (client Client) GetDeployment(name, namespace string) (*appsv1.Deployment, error) { - p, err := client.Clientset.AppsV1().Deployments(namespace).Get(context.Background(), name, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("the deployment '%v' in the namespace '%v' doesn't exist", name, namespace) - } - return p, nil -} - -func (client Client) GetDaemonSet(name, namespace string) (*appsv1.DaemonSet, error) { - p, err := client.Clientset.AppsV1().DaemonSets(namespace).Get(context.Background(), name, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("the daemonset '%v' in the namespace '%v' doesn't exist", name, namespace) - } - return p, nil -} - -func (client Client) GetStatefulSet(name, namespace string) (*appsv1.StatefulSet, error) { - p, err := client.Clientset.AppsV1().StatefulSets(namespace).Get(context.Background(), name, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("the statefulset '%v' in the namespace '%v' doesn't exist", name, namespace) - } - return p, nil -} - -func (client Client) GetReplicaSet(name, namespace string) (*appsv1.ReplicaSet, error) { - p, err := client.Clientset.AppsV1().ReplicaSets(namespace).Get(context.Background(), name, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("the replicaset '%v' in the namespace '%v' doesn't exist", name, namespace) - } - return p, nil -} - func (client Client) GetService(name, namespace string) (*corev1.Service, error) { p, err := client.Clientset.CoreV1().Services(namespace).Get(context.Background(), name, metav1.GetOptions{}) if err != nil { diff --git a/rules.yaml b/rules.yaml index 30b48d47..bdb8a90b 100644 --- a/rules.yaml +++ b/rules.yaml @@ -35,13 +35,13 @@ actions: - action: Labelize Pod as Suspicious -- rule: Delete resource +- rule: Calico netpol match: rules: - - Test resource + - Test Calico netpol output_fields: - k8s.ns.name!=kube-system actions: - - action: Delete resource - actionner: kubernetes:delete + - action: Create Calico netpol + actionner: calico:networkpolicy