Skip to content

Commit

Permalink
add cli tests and update readme (#64)
Browse files Browse the repository at this point in the history
* add cli tests and update readme

Signed-off-by: adisos <[email protected]>

* Update README.md

Co-authored-by: Ziv Nevo <[email protected]>

* Update README.md

Co-authored-by: Ziv Nevo <[email protected]>

* Update README.md

Co-authored-by: Ziv Nevo <[email protected]>

* Update README.md

Signed-off-by: adisos <[email protected]>
Co-authored-by: Ziv Nevo <[email protected]>
  • Loading branch information
adisos and zivnevo authored Jan 17, 2023
1 parent 52d25e2 commit e3ed702
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 6 deletions.
124 changes: 123 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,124 @@
# netpol-analyzer
A Golang library for analyzing connectivity-configuration resources (a.k.a. network policies)

## About netpol-analyzer
This repo contains a Golang library and CLI for analyzing k8s connectivity-configuration resources (a.k.a. network policies).


## CLI usage

### Evaluate command
```
Evaluate if a specific connection allowed
Usage:
k8snetpolicy evaluate [flags]
Aliases:
evaluate, eval, check, allow
Examples:
# Evaluate if a specific connection is allowed on given resources from dir path
k8snetpolicy eval --dirpath ./resources_dir/ -s pod-1 -d pod-2 -p 80
# Evaluate if a specific connection is allowed on a live k8s cluster
k8snetpolicy eval -k ./kube/config -s pod-1 -d pod-2 -p 80
Flags:
--destination-ip string Destination (external) IP address
--destination-namespace string Destination pod namespace (default "default")
-d, --destination-pod string Destination pod name
-p, --destination-port string Destination port (name or number)
-h, --help help for evaluate
--protocol string Protocol in use (tcp, udp, sctp) (default "tcp")
--source-ip string Source (external) IP address
-n, --source-namespace string Source pod namespace (default "default")
-s, --source-pod string Source pod name, required
Global Flags:
-c, --context string Kubernetes context to use when evaluating connections in a live cluster
--dirpath string Resources dir path when evaluating connections from a dir
-k, --kubeconfig string Path and file to use for kubeconfig when evaluating connections in a live cluster (default "/home/adisos/.kube/config")
```

### List command
```
Lists all allowed connections based on the workloads and network policies
defined
Usage:
k8snetpolicy list [flags]
Examples:
# Get list of allowed connections from resources dir path
k8snetpolicy list --dirpath ./resources_dir/
# Get list of allowed connections from live k8s cluster
k8snetpolicy list -k ./kube/config
Flags:
-h, --help help for list
Global Flags:
-c, --context string Kubernetes context to use when evaluating connections in a live cluster
--dirpath string Resources dir path when evaluating connections from a dir
-k, --kubeconfig string Path and file to use for kubeconfig when evaluating connections in a live cluster (default "/home/adisos/.kube/config")
```



### Example outputs:
```
$ k8snetpolicy eval --dirpath tests/onlineboutique -s adservice-77d5cd745d-t8mx4 -d emailservice-54c7c5d9d-vp27n -p 80
default/adservice-77d5cd745d-t8mx4 => default/emailservice-54c7c5d9d-vp27n over tcp/80: false
$ k8snetpolicy list --dirpath tests/onlineboutique_workloads
0.0.0.0-255.255.255.255 => default/redis-cart[Deployment] : All Connections
default/adservice[Deployment] => default/adservice[Deployment] : All Connections
default/cartservice[Deployment] => default/cartservice[Deployment] : All Connections
default/checkoutservice[Deployment] => default/cartservice[Deployment] : TCP 7070
default/checkoutservice[Deployment] => default/checkoutservice[Deployment] : All Connections
default/checkoutservice[Deployment] => default/currencyservice[Deployment] : TCP 7000
default/checkoutservice[Deployment] => default/emailservice[Deployment] : TCP 8080
default/checkoutservice[Deployment] => default/paymentservice[Deployment] : TCP 50051
default/checkoutservice[Deployment] => default/productcatalogservice[Deployment] : TCP 3550
default/checkoutservice[Deployment] => default/shippingservice[Deployment] : TCP 50051
default/currencyservice[Deployment] => default/currencyservice[Deployment] : All Connections
default/emailservice[Deployment] => default/emailservice[Deployment] : All Connections
default/frontend[Deployment] => default/adservice[Deployment] : TCP 9555
default/frontend[Deployment] => default/cartservice[Deployment] : TCP 7070
default/frontend[Deployment] => default/checkoutservice[Deployment] : TCP 5050
default/frontend[Deployment] => default/currencyservice[Deployment] : TCP 7000
default/frontend[Deployment] => default/frontend[Deployment] : All Connections
default/frontend[Deployment] => default/productcatalogservice[Deployment] : TCP 3550
default/frontend[Deployment] => default/recommendationservice[Deployment] : TCP 8080
default/frontend[Deployment] => default/shippingservice[Deployment] : TCP 50051
default/loadgenerator[Deployment] => default/frontend[Deployment] : TCP 8080
default/paymentservice[Deployment] => default/paymentservice[Deployment] : All Connections
default/productcatalogservice[Deployment] => default/productcatalogservice[Deployment] : All Connections
default/recommendationservice[Deployment] => default/productcatalogservice[Deployment] : TCP 3550
default/recommendationservice[Deployment] => default/recommendationservice[Deployment] : All Connections
default/redis-cart[Deployment] => 0.0.0.0-255.255.255.255 : All Connections
default/redis-cart[Deployment] => default/redis-cart[Deployment] : All Connections
default/shippingservice[Deployment] => default/shippingservice[Deployment] : All Connections
```

## Build the project

Make sure you have golang 1.18+ on your platform

```commandline
git clone [email protected]:np-guard/netpol-analyzer.git
cd netpol-analyzer
make mod
make build
```

Test your build by running `./bin/k8snetpolicy -h`.



159 changes: 159 additions & 0 deletions cmd/netpolicy/cmd/command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package cmd

import (
_ "embed"
"errors"
"io"
"os"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var (
stdoutFile *os.File
stderrFile *os.File
testOutR *os.File
testOutW *os.File
testErrR *os.File
testErrW *os.File

//go:embed tests_outputs/test_legal_list.txt
testLegalListOutput string
)

func preTestRun() {
stdoutFile = os.Stdout
stderrFile = os.Stderr
testOutR, testOutW, _ = os.Pipe()
os.Stdout = testOutW
testErrR, testErrW, _ = os.Pipe()
os.Stderr = testErrW
}

// finalize test and get its output
func postTestRun(isErr bool) string {
testOutW.Close()
testErrW.Close()
out, _ := io.ReadAll(testOutR)
errOut, _ := io.ReadAll(testErrR)
os.Stdout = stdoutFile
os.Stderr = stderrFile
actualOutput := string(out)
actualErr := string(errOut)
if isErr {
return actualErr
}
return actualOutput
}

func runTest(test cmdTest, t *testing.T) {
// run the test and get its output
preTestRun()
rootCmd.SetArgs(test.args)
err := rootCmd.Execute()
if !test.isErr {
require.Nilf(t, err, "expected no errors, but got %v", err)
} else {
require.NotNil(t, err, "expected error, but got no error")
}
actual := postTestRun(test.isErr)

// compare actual to test.expectedOutput
if test.exact {
assert.Equal(t, test.expectedOutput, actual, "error - unexpected output")
} else if test.containment {
isContained := strings.Contains(actual, test.expectedOutput)
assert.True(t, isContained, "test %s error: %s not contained in %s", test.name, test.expectedOutput, actual)
} else {
assert.Error(t, errors.New(""), "test %s: missing containment or equality flag for test")
}
}

type cmdTest struct {
name string
args []string
expectedOutput string
exact bool
containment bool
isErr bool
}

func TestCommannds(t *testing.T) {
tests := []cmdTest{
{
name: "test_illegal_command",
args: []string{"A"},
expectedOutput: "Error: unknown command \"A\" for \"k8snetpolicy\"",
containment: true,
isErr: true,
},

{
name: "test_illegal_eval_no_args",
args: []string{"eval"},
expectedOutput: "no source defined",
containment: true,
isErr: true,
},

{
name: "test_illegal_eval_peer_not_found",
args: []string{
"eval",
"--dirpath",
filepath.Join(getTestsDir(), "onlineboutique"),
"-s",
"default/adservice-77d5cd745d-t8mx4",
"-d",
"default/emailservice-54c7c5d9d-vp27n",
"-p",
"80"},
expectedOutput: "could not find peer default/default/adservice-77d5cd745d",
containment: true,
isErr: true,
},

{
name: "test_legal_eval",
args: []string{
"eval",
"--dirpath",
filepath.Join(getTestsDir(), "onlineboutique"),
"-s",
"adservice-77d5cd745d-t8mx4",
"-d",
"emailservice-54c7c5d9d-vp27n",
"-p",
"80"},
expectedOutput: "default/adservice-77d5cd745d-t8mx4 => default/emailservice-54c7c5d9d-vp27n over tcp/80: false\n",
exact: true,
isErr: false,
},

{
name: "test_legal_list",
args: []string{
"list",
"--dirpath",
filepath.Join(getTestsDir(), "onlineboutique"),
},
expectedOutput: testLegalListOutput,
exact: true,
isErr: false,
},
}

for _, test := range tests {
runTest(test, t)
}
}

func getTestsDir() string {
currentDir, _ := os.Getwd()
res := filepath.Join(currentDir, "..", "..", "..", "tests")
return res
}
4 changes: 2 additions & 2 deletions cmd/netpolicy/cmd/evaluate.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ var evaluateCmd = &cobra.Command{
Short: "Evaluate if a specific connection allowed",
Aliases: []string{"eval", "check", "allow"}, // TODO: close on fewer, consider changing command name?
Example: ` # Evaluate if a specific connection is allowed on given resources from dir path
k8snetpolicy eval --dirpath ./resources_dir/ -s default/pod-1 -d default/pod-2 -p 80
k8snetpolicy eval --dirpath ./resources_dir/ -s pod-1 -d pod-2 -p 80
# Evaluate if a specific connection is allowed on a live k8s cluster
k8snetpolicy eval -k ./kube/config -s default/pod-1 -d default/pod-2 -p 80`,
k8snetpolicy eval -k ./kube/config -s pod-1 -d pod-2 -p 80`,

// TODO: can this check be done in an Args function (e.g., incl. built-in's such as MinArgs(3))?
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
Expand Down
29 changes: 29 additions & 0 deletions cmd/netpolicy/cmd/tests_outputs/test_legal_list.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
0.0.0.0-255.255.255.255 => default/redis-cart-78746d49dc[ReplicaSet] : All Connections
default/adservice-77d5cd745d[ReplicaSet] => default/adservice-77d5cd745d[ReplicaSet] : All Connections
default/cartservice-74f56fd4b[ReplicaSet] => default/cartservice-74f56fd4b[ReplicaSet] : All Connections
default/checkoutservice-69c8ff664b[ReplicaSet] => default/cartservice-74f56fd4b[ReplicaSet] : TCP 7070
default/checkoutservice-69c8ff664b[ReplicaSet] => default/checkoutservice-69c8ff664b[ReplicaSet] : All Connections
default/checkoutservice-69c8ff664b[ReplicaSet] => default/currencyservice-77654bbbdd[ReplicaSet] : TCP 7000
default/checkoutservice-69c8ff664b[ReplicaSet] => default/emailservice-54c7c5d9d[ReplicaSet] : TCP 8080
default/checkoutservice-69c8ff664b[ReplicaSet] => default/paymentservice-bbcbdc6b6[ReplicaSet] : TCP 50051
default/checkoutservice-69c8ff664b[ReplicaSet] => default/productcatalogservice-68765d49b6[ReplicaSet] : TCP 3550
default/checkoutservice-69c8ff664b[ReplicaSet] => default/shippingservice-5bd985c46d[ReplicaSet] : TCP 50051
default/currencyservice-77654bbbdd[ReplicaSet] => default/currencyservice-77654bbbdd[ReplicaSet] : All Connections
default/emailservice-54c7c5d9d[ReplicaSet] => default/emailservice-54c7c5d9d[ReplicaSet] : All Connections
default/frontend-99684f7f8[ReplicaSet] => default/adservice-77d5cd745d[ReplicaSet] : TCP 9555
default/frontend-99684f7f8[ReplicaSet] => default/cartservice-74f56fd4b[ReplicaSet] : TCP 7070
default/frontend-99684f7f8[ReplicaSet] => default/checkoutservice-69c8ff664b[ReplicaSet] : TCP 5050
default/frontend-99684f7f8[ReplicaSet] => default/currencyservice-77654bbbdd[ReplicaSet] : TCP 7000
default/frontend-99684f7f8[ReplicaSet] => default/frontend-99684f7f8[ReplicaSet] : All Connections
default/frontend-99684f7f8[ReplicaSet] => default/productcatalogservice-68765d49b6[ReplicaSet] : TCP 3550
default/frontend-99684f7f8[ReplicaSet] => default/recommendationservice-5f8c456796[ReplicaSet] : TCP 8080
default/frontend-99684f7f8[ReplicaSet] => default/shippingservice-5bd985c46d[ReplicaSet] : TCP 50051
default/loadgenerator-555fbdc87d[ReplicaSet] => default/frontend-99684f7f8[ReplicaSet] : TCP 8080
default/loadgenerator-555fbdc87d[ReplicaSet] => default/loadgenerator-555fbdc87d[ReplicaSet] : All Connections
default/paymentservice-bbcbdc6b6[ReplicaSet] => default/paymentservice-bbcbdc6b6[ReplicaSet] : All Connections
default/productcatalogservice-68765d49b6[ReplicaSet] => default/productcatalogservice-68765d49b6[ReplicaSet] : All Connections
default/recommendationservice-5f8c456796[ReplicaSet] => default/productcatalogservice-68765d49b6[ReplicaSet] : TCP 3550
default/recommendationservice-5f8c456796[ReplicaSet] => default/recommendationservice-5f8c456796[ReplicaSet] : All Connections
default/redis-cart-78746d49dc[ReplicaSet] => 0.0.0.0-255.255.255.255 : All Connections
default/redis-cart-78746d49dc[ReplicaSet] => default/redis-cart-78746d49dc[ReplicaSet] : All Connections
default/shippingservice-5bd985c46d[ReplicaSet] => default/shippingservice-5bd985c46d[ReplicaSet] : All Connections
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ go 1.18
require (
github.com/hashicorp/golang-lru v0.5.4
github.com/spf13/cobra v1.5.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
github.com/stretchr/testify v1.8.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.24.2
k8s.io/apimachinery v0.24.2
k8s.io/client-go v0.24.2
Expand Down Expand Up @@ -34,6 +35,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
Expand Down
10 changes: 8 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,17 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down Expand Up @@ -611,8 +616,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
Expand Down

0 comments on commit e3ed702

Please sign in to comment.