Skip to content

Commit

Permalink
add new actionner calico:networkpolicy (#173)
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas Labarussias <issif+github@gadz.org>
  • Loading branch information
Issif authored Feb 13, 2024
1 parent ee78f7d commit 9e329e3
Show file tree
Hide file tree
Showing 10 changed files with 409 additions and 147 deletions.
35 changes: 25 additions & 10 deletions actionners/actionners.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand All @@ -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,
},
)
}

Expand Down
183 changes: 183 additions & 0 deletions actionners/calico/networkpolicy/networkpolicy.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 9e329e3

Please sign in to comment.