Skip to content

Commit

Permalink
Merge pull request #159 from Issif/refacto-netpol
Browse files Browse the repository at this point in the history
refactorisation of the kubernetes:netpol actionner
  • Loading branch information
Issif authored Dec 20, 2023
2 parents 1f92d59 + 853624f commit 3a51f2a
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 109 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,14 @@ Several rules can match same event, so several action can be triggered, except f

### `kubernetes:networkpolicy`

* Description: **Create, update a network policy to block the egress**
* Description: **Create, update a network policy to block all egress traffic for pod**
* Continue: `true`
* Before: `true`
* Parameters: N/A
* Parameters:
* `allow`: list of CIDR to allow anyway (eg: private subnets)
* Required fields:
* `k8s.pod.name`
* `k8s.ns.name`
* `fd.sip` or `fd.rip`
* `fd.sport` or `fd.rport`

### `kubernetes:exec`

Expand Down
5 changes: 1 addition & 4 deletions actionners/actionners.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package actionners

import (
"github.com/Issif/falco-talon/actionners/checks"
"github.com/Issif/falco-talon/actionners/kubernetes/exec"
labelize "github.com/Issif/falco-talon/actionners/kubernetes/labelize"
networkpolicy "github.com/Issif/falco-talon/actionners/kubernetes/networkpolicy"
Expand Down Expand Up @@ -63,10 +62,8 @@ func GetDefaultActionners() *Actionners {
Init: kubernetes.Init,
Checks: []checkActionner{
kubernetes.CheckPodExist,
checks.CheckRemoteIP,
checks.CheckRemotePort,
},
CheckParameters: nil,
CheckParameters: networkpolicy.CheckParameters,
Action: networkpolicy.NetworkPolicy,
},
&Actionner{
Expand Down
136 changes: 59 additions & 77 deletions actionners/kubernetes/networkpolicy/networkpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ package networkpolicy
import (
"context"
"fmt"
"strconv"
"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"
"k8s.io/apimachinery/pkg/util/intstr"

"github.com/Issif/falco-talon/internal/events"
kubernetes "github.com/Issif/falco-talon/internal/kubernetes/client"
Expand Down Expand Up @@ -161,7 +160,21 @@ var NetworkPolicy = func(rule *rules.Rule, event *events.Event) (utils.LogLine,

delete(labels, "pod-template-hash")

np, err := createEgressRule(event)
payload := networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: owner,
Namespace: namespace,
Labels: labels,
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{"Egress"},
PodSelector: metav1.LabelSelector{
MatchLabels: labels,
},
},
}

np, err := createEgressRule(rule)
if err != nil {
return utils.LogLine{
Objects: objects,
Expand All @@ -171,46 +184,27 @@ var NetworkPolicy = func(rule *rules.Rule, event *events.Event) (utils.LogLine,
err
}

if np != nil {
payload.Spec.Egress = []networkingv1.NetworkPolicyEgressRule{*np}
}

var status string
n, err := client.NetworkingV1().NetworkPolicies(namespace).Get(context.Background(), owner, metav1.GetOptions{})
_, err = client.NetworkingV1().NetworkPolicies(namespace).Get(context.Background(), owner, metav1.GetOptions{})
if errorsv1.IsNotFound(err) {
payload := networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: owner,
Namespace: namespace,
Labels: labels,
},
Spec: networkingv1.NetworkPolicySpec{
PolicyTypes: []networkingv1.PolicyType{"Egress"},
PodSelector: metav1.LabelSelector{
MatchLabels: labels,
},
Egress: []networkingv1.NetworkPolicyEgressRule{np},
},
}
_, err = client.NetworkingV1().NetworkPolicies(namespace).Create(context.Background(), &payload, metav1.CreateOptions{})
if err != nil {
return utils.LogLine{
Objects: objects,
Error: err.Error(),
Status: "failure",
},
err
}
status = "created"
} else {
n.Spec.Egress = append(n.Spec.Egress, np)
_, err = client.NetworkingV1().NetworkPolicies(namespace).Update(context.Background(), n, metav1.UpdateOptions{})
if err != nil {
return utils.LogLine{
Objects: objects,
Error: err.Error(),
Status: "failure",
},
err
}
_, err = client.NetworkingV1().NetworkPolicies(namespace).Update(context.Background(), &payload, metav1.UpdateOptions{})
status = "updated"
}
if err != nil {
return utils.LogLine{
Objects: objects,
Error: err.Error(),
Status: "failure",
},
err
}
objects["NetworkPolicy"] = owner
return utils.LogLine{
Objects: objects,
Expand All @@ -220,52 +214,40 @@ var NetworkPolicy = func(rule *rules.Rule, event *events.Event) (utils.LogLine,
nil
}

func createEgressRule(event *events.Event) (networkingv1.NetworkPolicyEgressRule, error) {
ips, ports := extractIPsPorts(event)
er := networkingv1.NetworkPolicyEgressRule{
To: []networkingv1.NetworkPolicyPeer{},
Ports: []networkingv1.NetworkPolicyPort{},
}
for _, i := range ips {
er.To = append(er.To, networkingv1.NetworkPolicyPeer{
IPBlock: &networkingv1.IPBlock{
CIDR: fmt.Sprintf("%v/32", i),
},
})
func createEgressRule(rule *rules.Rule) (*networkingv1.NetworkPolicyEgressRule, error) {
if rule.Action.Parameters["allow"] == nil {
return nil, nil
}
for _, i := range ports {
er.Ports = append(er.Ports, networkingv1.NetworkPolicyPort{
Port: &intstr.IntOrString{
IntVal: i,
},
})
np := make([]networkingv1.NetworkPolicyPeer, 0)
ex := rule.Action.Parameters["allow"].([]interface{})
if len(ex) != 0 {
for _, i := range ex {
np = append(np,
networkingv1.NetworkPolicyPeer{
IPBlock: &networkingv1.IPBlock{
CIDR: i.(string),
},
},
)
}
}
return er, nil
return &networkingv1.NetworkPolicyEgressRule{To: np}, nil
}

func extractIPsPorts(event *events.Event) ([]string, []int32) {
ips, ports := []string{}, []int32{}
for i, j := range event.OutputFields {
if i == "fd.sip" {
ips = append(ips, j.(string))
}
if i == "fd.rip" {
ips = append(ips, j.(string))
}
if i == "fd.sport" {
p := fmt.Sprintf("%v", j)
k, err := strconv.ParseInt(p, 10, 64)
if err == nil {
ports = append(ports, int32(k))
}
}
if i == "fd.rport" {
p := fmt.Sprintf("%v", j)
k, err := strconv.ParseInt(p, 10, 64)
if err == nil {
ports = append(ports, int32(k))
var CheckParameters = func(rule *rules.Rule) error {
parameters := rule.GetParameters()
if err := utils.CheckParameters(parameters, "allow", utils.SliceInterfaceStr, nil, false); err != nil {
return err
}
if parameters["allow"] == nil {
return nil
}
if p := parameters["allow"].([]interface{}); len(p) != 0 {
for _, i := range p {
if _, _, err := net.ParseCIDR(i.(string)); err != nil {
return fmt.Errorf("wrong CIDR '%v'", i)
}
}
}
return ips, ports
return nil
}
20 changes: 5 additions & 15 deletions rules.yaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
- name: Rule Test Script
match:
rules:
- Test Script
action:
name: kubernetes:script
parameters:
shell: sh
script: |
#!/bin/sh
uname
uname -r
uname -a
echo "hello world"
- name: Rule Test NetworkPolicy
match:
rules:
- DANGER UNWANTED outbound connection destination
- Test NetPol
action:
name: kubernetes:networkpolicy
parameters:
allow:
- "192.168.1.0/24"
- "172.17.0.0/16"
- "10.0.0.0/32"
continue: true
19 changes: 10 additions & 9 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@ import (
)

const (
BoolStr string = "bool"
FloatStr string = "float"
Float64Str string = "float64"
StringStr string = "string"
IntStr string = "int"
Int64Str string = "int64"
MapStringStr string = "map[string]string"
MapIntStr string = "map[string]int"
MapInterfaceStr string = "map[string]interface {}"
BoolStr string = "bool"
FloatStr string = "float"
Float64Str string = "float64"
StringStr string = "string"
IntStr string = "int"
Int64Str string = "int64"
SliceInterfaceStr string = "[]interface {}"
MapStringStr string = "map[string]string"
MapIntStr string = "map[string]int"
MapInterfaceStr string = "map[string]interface {}"

errorStr string = "error"
warningStr string = "warning"
Expand Down

0 comments on commit 3a51f2a

Please sign in to comment.