From 6f6cad5613294cc8b4c2c8a245943828e6076b3d Mon Sep 17 00:00:00 2001 From: Michael Fornaro <20387402+xUnholy@users.noreply.github.com> Date: Tue, 12 Sep 2023 20:46:16 +1000 Subject: [PATCH 1/4] feat: implement cobra cli Signed-off-by: Michael Fornaro <20387402+xUnholy@users.noreply.github.com> --- advisor/cmd/main.go | 134 ----------------------------- advisor/cmd/root.go | 57 ++++++++++++ advisor/go.mod | 3 + advisor/go.sum | 8 ++ advisor/main.go | 9 ++ advisor/pkg/k8s/networkpolicies.go | 125 +++++++++++++++++++++++++++ 6 files changed, 202 insertions(+), 134 deletions(-) delete mode 100644 advisor/cmd/main.go create mode 100644 advisor/cmd/root.go create mode 100644 advisor/main.go diff --git a/advisor/cmd/main.go b/advisor/cmd/main.go deleted file mode 100644 index 6edce5d14..000000000 --- a/advisor/cmd/main.go +++ /dev/null @@ -1,134 +0,0 @@ -package main - -import ( - "fmt" - "log" - - db "github.com/arx-inc/advisor/pkg/database" - "github.com/arx-inc/advisor/pkg/k8s" - v1 "k8s.io/api/core/v1" - networkingv1 "k8s.io/api/networking/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" - "sigs.k8s.io/yaml" -) - -const ( - // TODO: Remove these hardcoded values - name = "test-network-policy" - namespace = "default" - - // TODO: replace these with your actual PostgreSQL connection details - host = "localhost" - port = 5432 - user = "youruser" - password = "yourpassword" - dbname = "yourdb" -) - -func main() { - - // Decide whether to use real DB or stub - var podTrafficGetter db.PodTrafficGetter - useDB := false // change this to false to use the stub - - if useDB { - var err error - podTrafficGetter, err = db.NewDBConnection(host, port, user, password, dbname) - if err != nil { - log.Fatalf("Error opening database connection: %v\n", err) - return - } - defer podTrafficGetter.(*db.DBConnection).Close() - } else { - podTrafficGetter = &db.PodTrafficStub{} - } - - // example of querying for a specific UUID - podName := "dummy-src-pod" - podTraffic, err := podTrafficGetter.GetPodTraffic(podName) - if err != nil { - log.Fatalf("Error retrieving pod traffic: %v\n", err) - return - } - - if podTraffic != nil { - fmt.Printf("Pod traffic for pod %s: %+v\n", podName, podTraffic) - } else { - fmt.Printf("No pod traffic found for pod %s\n", podName) - } - - podSpec, err := podTrafficGetter.GetPodSpec(podTraffic.SrcPodName) - if err != nil { - log.Fatalf("Error retrieving pod spec: %v\n", err) - return - } - - if podSpec != nil { - fmt.Printf("Pod spec for pod %s: %+v\n", podSpec.Name, podSpec.Spec) - } else { - fmt.Printf("No pod spec found for pod %s\n", podSpec) - } - - // TODO: replace this with your actual network policy spec from the database - spec := k8s.NetworkPolicySpec{ - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "MyApp", - }, - }, - PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress, networkingv1.PolicyTypeEgress}, - Ingress: []k8s.NetworkPolicyRule{ - { - Ports: []networkingv1.NetworkPolicyPort{ - { - Protocol: protoPtr(v1.ProtocolTCP), - Port: intStrPtr(8080), - }, - }, - FromTo: []networkingv1.NetworkPolicyPeer{ - { - PodSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "access": "allowed", - }, - }, - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "kubernetes.io/metadata.name:": "some-namespace", - }, - }, - }, - }, - }, - }, - Egress: []k8s.NetworkPolicyRule{ - { - // No ports specified, so all ports are allowed - Ports: []networkingv1.NetworkPolicyPort{}, - FromTo: []networkingv1.NetworkPolicyPeer{ - { - // No pod selector or namespace selector specified, so all destinations are allowed - }, - }, - }, - }, - } - - policy := k8s.CreateNetworkPolicy(name, namespace, spec) - policyYAML, err := yaml.Marshal(policy) - if err != nil { - fmt.Printf("Error converting policy to YAML: %v", err) - return - } - - fmt.Println(string(policyYAML)) -} - -func protoPtr(protocol v1.Protocol) *v1.Protocol { - return &protocol -} - -func intStrPtr(port int32) *intstr.IntOrString { - return &intstr.IntOrString{IntVal: port} -} diff --git a/advisor/cmd/root.go b/advisor/cmd/root.go new file mode 100644 index 000000000..515dc959f --- /dev/null +++ b/advisor/cmd/root.go @@ -0,0 +1,57 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/arx-inc/advisor/pkg/k8s" + "github.com/spf13/cobra" +) + +func init() { + genCmd.AddCommand(networkPolicyCmd, seccompCmd) + rootCmd.AddCommand(genCmd) +} + +var rootCmd = &cobra.Command{ + Use: "arx", + Short: "Arx is a security tool for enhancing Kubernetes application profiles", + Long: `Arx is designed to improve the security profile of applications running in + Kubernetes clusters. It provides various functionalities like generating network + policies, seccomp profiles, and more to ensure that your applications meet + best security practices. + Complete documentation is available at [Your Documentation URL]`, +} + +var genCmd = &cobra.Command{ + Use: "gen", + Short: "Generate resources", +} + +var networkPolicyCmd = &cobra.Command{ + Use: "networkpolicy [pod-name]", + Short: "Generate network policy", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + podName := args[0] + fmt.Printf("Generating network policy for pod: %s\n", podName) + k8s.GenerateNetworkPolicy(podName) + }, +} + +var seccompCmd = &cobra.Command{ + Use: "seccomp [pod-name]", + Short: "Generate seccomp profile", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + podName := args[0] + fmt.Printf("Generating seccomp profile for pod: %s\n", podName) + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/advisor/go.mod b/advisor/go.mod index e82106649..d19dac8e2 100644 --- a/advisor/go.mod +++ b/advisor/go.mod @@ -12,10 +12,13 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gofuzz v1.1.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/lib/pq v1.10.9 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.8.0 // indirect golang.org/x/text v0.11.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/advisor/go.sum b/advisor/go.sum index 823fdff1b..5e58efe69 100644 --- a/advisor/go.sum +++ b/advisor/go.sum @@ -1,3 +1,4 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -10,6 +11,8 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -25,7 +28,11 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= @@ -68,6 +75,7 @@ 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= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/api v0.26.6 h1:RZsJGP5p/qdWuFVqj/JFyt+6ttfgL+8/K8gtyi7riuo= k8s.io/api v0.26.6/go.mod h1:Z+i6M3de4+LJiXtIiWSz/yLpnG+YjxAkeW6cgZqoxn4= k8s.io/apimachinery v0.26.6 h1:OT04J9US8G+AqfqvcJZZ8s3WUQkWbc3t6ePPWieDN6I= diff --git a/advisor/main.go b/advisor/main.go new file mode 100644 index 000000000..d9e7c50b4 --- /dev/null +++ b/advisor/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/arx-inc/advisor/cmd" +) + +func main() { + cmd.Execute() +} diff --git a/advisor/pkg/k8s/networkpolicies.go b/advisor/pkg/k8s/networkpolicies.go index 085d60461..851aaf9db 100644 --- a/advisor/pkg/k8s/networkpolicies.go +++ b/advisor/pkg/k8s/networkpolicies.go @@ -1,8 +1,28 @@ package k8s import ( + "fmt" + "log" + + db "github.com/arx-inc/advisor/pkg/database" + v1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/yaml" +) + +const ( + // TODO: Remove these hardcoded values + name = "test-network-policy" + namespace = "default" + + // TODO: replace these with your actual PostgreSQL connection details + host = "localhost" + port = 5432 + user = "youruser" + password = "yourpassword" + dbname = "yourdb" ) type NetworkPolicyRule struct { @@ -17,6 +37,103 @@ type NetworkPolicySpec struct { Egress []NetworkPolicyRule } +func GenerateNetworkPolicy(podName string) { + // Decide whether to use real DB or stub + var podTrafficGetter db.PodTrafficGetter + useDB := false // change this to false to use the stub + + if useDB { + var err error + podTrafficGetter, err = db.NewDBConnection(host, port, user, password, dbname) + if err != nil { + log.Fatalf("Error opening database connection: %v\n", err) + return + } + defer podTrafficGetter.(*db.DBConnection).Close() + } else { + podTrafficGetter = &db.PodTrafficStub{} + } + + // example of querying for a specific UUID + podTraffic, err := podTrafficGetter.GetPodTraffic(podName) + if err != nil { + log.Fatalf("Error retrieving pod traffic: %v\n", err) + return + } + + if podTraffic != nil { + fmt.Printf("Pod traffic for pod %s: %+v\n", podName, podTraffic) + } else { + fmt.Printf("No pod traffic found for pod %s\n", podName) + } + + podSpec, err := podTrafficGetter.GetPodSpec(podTraffic.SrcPodName) + if err != nil { + log.Fatalf("Error retrieving pod spec: %v\n", err) + return + } + + if podSpec != nil { + fmt.Printf("Pod spec for pod %s: %+v\n", podSpec.Name, podSpec.Spec) + } else { + fmt.Printf("No pod spec found for pod %s\n", podSpec) + } + + // TODO: replace this with your actual network policy spec from the database + spec := NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "MyApp", + }, + }, + PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress, networkingv1.PolicyTypeEgress}, + Ingress: []NetworkPolicyRule{ + { + Ports: []networkingv1.NetworkPolicyPort{ + { + Protocol: protoPtr(v1.ProtocolTCP), + Port: intStrPtr(8080), + }, + }, + FromTo: []networkingv1.NetworkPolicyPeer{ + { + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "access": "allowed", + }, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "kubernetes.io/metadata.name:": "some-namespace", + }, + }, + }, + }, + }, + }, + Egress: []NetworkPolicyRule{ + { + // No ports specified, so all ports are allowed + Ports: []networkingv1.NetworkPolicyPort{}, + FromTo: []networkingv1.NetworkPolicyPeer{ + { + // No pod selector or namespace selector specified, so all destinations are allowed + }, + }, + }, + }, + } + + policy := CreateNetworkPolicy(name, namespace, spec) + policyYAML, err := yaml.Marshal(policy) + if err != nil { + fmt.Printf("Error converting policy to YAML: %v", err) + return + } + + fmt.Println(string(policyYAML)) +} + func CreateNetworkPolicy(name, namespace string, spec NetworkPolicySpec) *networkingv1.NetworkPolicy { networkPolicy := &networkingv1.NetworkPolicy{ TypeMeta: metav1.TypeMeta{ @@ -49,3 +166,11 @@ func CreateNetworkPolicy(name, namespace string, spec NetworkPolicySpec) *networ return networkPolicy } + +func protoPtr(protocol v1.Protocol) *v1.Protocol { + return &protocol +} + +func intStrPtr(port int32) *intstr.IntOrString { + return &intstr.IntOrString{IntVal: port} +} From a49fccbe401dd8a425563bc0cdcb610d1bac16e7 Mon Sep 17 00:00:00 2001 From: Michael Fornaro <20387402+xUnholy@users.noreply.github.com> Date: Tue, 12 Sep 2023 20:47:41 +1000 Subject: [PATCH 2/4] chore: add all files Signed-off-by: Michael Fornaro <20387402+xUnholy@users.noreply.github.com> --- main.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 main.go diff --git a/main.go b/main.go new file mode 100644 index 000000000..e69de29bb From 6be6655a8a19b907c7856bac02e90e2220d04c99 Mon Sep 17 00:00:00 2001 From: Michael Fornaro <20387402+xUnholy@users.noreply.github.com> Date: Wed, 13 Sep 2023 20:17:45 +1000 Subject: [PATCH 3/4] feat: added client portforward, imrpoved netpol generatior, api to the broker and more Signed-off-by: Michael Fornaro <20387402+xUnholy@users.noreply.github.com> --- README.md | 74 +++++++++++ advisor/cmd/gen.go | 60 +++++++++ advisor/cmd/root.go | 30 +---- advisor/go.mod | 41 +++++-- advisor/go.sum | 78 ++++++++++++ advisor/main.go | 0 advisor/pkg/api/pod_traffic.go | 135 ++++++++++++++++++++ advisor/pkg/database/db.go | 119 ------------------ advisor/pkg/k8s/auth.go | 71 +++++++++++ advisor/pkg/k8s/networkpolicies.go | 190 ++++++++++++----------------- advisor/pkg/k8s/portforward.go | 72 +++++++++++ 11 files changed, 603 insertions(+), 267 deletions(-) create mode 100644 README.md create mode 100644 advisor/cmd/gen.go mode change 100644 => 100755 advisor/main.go create mode 100644 advisor/pkg/api/pod_traffic.go delete mode 100644 advisor/pkg/database/db.go create mode 100644 advisor/pkg/k8s/auth.go create mode 100644 advisor/pkg/k8s/portforward.go diff --git a/README.md b/README.md new file mode 100644 index 000000000..6abda3649 --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +# ARX: Advisor for Kubernetes + +ARX is a powerful kubectl plugin designed to enhance the security of your Kubernetes clusters. The Advisor component allows users to automatically generate crucial security resources like Network Policies, Seccomp Profiles, and more for Kubernetes pods or services. + +## Table of Contents +- [ARX: Advisor for Kubernetes](#arx-advisor-for-kubernetes) + - [Table of Contents](#table-of-contents) + - [🌟 Features](#-features) + - [🛠️ Prequisites](#️-prequisites) + - [📦 Installation](#-installation) + - [🔨 Usage](#-usage) + - [🔒 Generate Network Policies](#-generate-network-policies) + - [🛡️ Generate Seccomp Profiles](#️-generate-seccomp-profiles) + - [🤝 Contributing](#-contributing) + - [📄 License](#-license) + - [🙏 Acknowledgments](#-acknowledgments) + +## 🌟 Features + +WIP + +## 🛠️ Prequisites + +- Kubernetes cluster v1.18+ +- kubectl v1.18+ + +## 📦 Installation + +You can install ARX via Krew, the plugin manager for kubectl: + +```bash +kubectl krew install arx +``` + +Or manually download the release and place it in your PATH: + +```bash +# Download the release and set it as executable +wget https://github.com/arx-inc/advisor/releases/download/v1.0.0/arx +chmod +x arx +mv arx /usr/local/bin/ +``` + +## 🔨 Usage + +### 🔒 Generate Network Policies + +```bash +kubectl arx gen networkpolicy [pod-name] --namespace my-namespace +``` + +### 🛡️ Generate Seccomp Profiles + +```bash +kubectl arx gen seccomp [pod-name] --namespace my-namespace +``` + +For more details on the commands: + +```bash +kubectl arx --help +``` + +## 🤝 Contributing + +Contributions are welcome! Please read the contributing guide to get started. + +## 📄 License + +This project is licensed under the [PLACEHOLDER] License - see the [LICENSE.md](LICENSE.md) file for details. + +## 🙏 Acknowledgments + +Thanks to the Kubernetes community for the excellent tools and libraries. diff --git a/advisor/cmd/gen.go b/advisor/cmd/gen.go new file mode 100644 index 000000000..02f6db65e --- /dev/null +++ b/advisor/cmd/gen.go @@ -0,0 +1,60 @@ +package cmd + +import ( + "fmt" + "log" + "os" + + "github.com/arx-inc/advisor/pkg/k8s" + "github.com/spf13/cobra" +) + +var genCmd = &cobra.Command{ + Use: "gen", + Short: "Generate resources", +} + +var networkPolicyCmd = &cobra.Command{ + Use: "networkpolicy [pod-name]", + Aliases: []string{"netpol"}, + Short: "Generate network policy", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + + kubeconfig, _ := cmd.Flags().GetString("kubeconfig") + namespace, _ := cmd.Flags().GetString("namespace") + + config, err := k8s.NewConfig(kubeconfig, namespace) + if err != nil { + fmt.Println("Error initializing Kubernetes client:", err) + os.Exit(1) + } + + fmt.Printf("Using kubeconfig file: %s\n", config.Kubeconfig) + fmt.Printf("Using namespace: %s\n", config.Namespace) + + podName := args[0] + + stopChan, errChan, done := k8s.PortForward(config) + <-done // Block until we receive a notification from the goroutine that port-forwarding has been set up + go func() { + for err := range errChan { + log.Fatalf("Failed to start port-forwarding: %v", err) + } + }() + fmt.Println("Port forwarding set up successfully.") + k8s.GenerateNetworkPolicy(podName, config.Namespace) + close(stopChan) + }, +} + +var seccompCmd = &cobra.Command{ + Use: "seccomp [pod-name]", + Aliases: []string{"sc"}, + Short: "Generate seccomp profile", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + podName := args[0] + fmt.Printf("Generating seccomp profile for pod: %s\n", podName) + }, +} diff --git a/advisor/cmd/root.go b/advisor/cmd/root.go index 515dc959f..d37f8340d 100644 --- a/advisor/cmd/root.go +++ b/advisor/cmd/root.go @@ -4,12 +4,14 @@ import ( "fmt" "os" - "github.com/arx-inc/advisor/pkg/k8s" "github.com/spf13/cobra" ) func init() { genCmd.AddCommand(networkPolicyCmd, seccompCmd) + genCmd.PersistentFlags().String("kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.") + genCmd.PersistentFlags().String("namespace", "", "If present, the namespace scope for this CLI request") + rootCmd.AddCommand(genCmd) } @@ -23,32 +25,6 @@ var rootCmd = &cobra.Command{ Complete documentation is available at [Your Documentation URL]`, } -var genCmd = &cobra.Command{ - Use: "gen", - Short: "Generate resources", -} - -var networkPolicyCmd = &cobra.Command{ - Use: "networkpolicy [pod-name]", - Short: "Generate network policy", - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - podName := args[0] - fmt.Printf("Generating network policy for pod: %s\n", podName) - k8s.GenerateNetworkPolicy(podName) - }, -} - -var seccompCmd = &cobra.Command{ - Use: "seccomp [pod-name]", - Short: "Generate seccomp profile", - Args: cobra.ExactArgs(1), - Run: func(cmd *cobra.Command, args []string) { - podName := args[0] - fmt.Printf("Generating seccomp profile for pod: %s\n", podName) - }, -} - func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Println(err) diff --git a/advisor/go.mod b/advisor/go.mod index d19dac8e2..8ba8f52c6 100644 --- a/advisor/go.mod +++ b/advisor/go.mod @@ -3,28 +3,53 @@ module github.com/arx-inc/advisor go 1.20 require ( - k8s.io/api v0.26.6 - k8s.io/apimachinery v0.26.6 + k8s.io/api v0.28.1 + k8s.io/apimachinery v0.28.1 sigs.k8s.io/yaml v1.3.0 + + ) require ( - github.com/go-logr/logr v1.2.3 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gofuzz v1.1.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/imdario/mergo v0.3.6 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/lib/pq v1.10.9 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/moby/spdystream v0.2.0 // indirect 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/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/net v0.8.0 // indirect + golang.org/x/net v0.13.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/klog/v2 v2.80.1 // indirect - k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect - sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/client-go v0.28.1 // indirect + k8s.io/klog/v2 v2.100.1 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/advisor/go.sum b/advisor/go.sum index 5e58efe69..52e110f28 100644 --- a/advisor/go.sum +++ b/advisor/go.sum @@ -1,30 +1,68 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -34,8 +72,14 @@ github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRM 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/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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -44,21 +88,33 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -67,25 +123,47 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 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= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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= k8s.io/api v0.26.6 h1:RZsJGP5p/qdWuFVqj/JFyt+6ttfgL+8/K8gtyi7riuo= k8s.io/api v0.26.6/go.mod h1:Z+i6M3de4+LJiXtIiWSz/yLpnG+YjxAkeW6cgZqoxn4= +k8s.io/api v0.28.1 h1:i+0O8k2NPBCPYaMB+uCkseEbawEt/eFaiRqUx8aB108= +k8s.io/api v0.28.1/go.mod h1:uBYwID+66wiL28Kn2tBjBYQdEU0Xk0z5qF8bIBqk/Dg= k8s.io/apimachinery v0.26.6 h1:OT04J9US8G+AqfqvcJZZ8s3WUQkWbc3t6ePPWieDN6I= k8s.io/apimachinery v0.26.6/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0= +k8s.io/apimachinery v0.28.1 h1:EJD40og3GizBSV3mkIoXQBsws32okPOy+MkRyzh6nPY= +k8s.io/apimachinery v0.28.1/go.mod h1:X0xh/chESs2hP9koe+SdIAcXWcQ+RM5hy0ZynB+yEvw= +k8s.io/client-go v0.28.1 h1:pRhMzB8HyLfVwpngWKE8hDcXRqifh1ga2Z/PU9SXVK8= +k8s.io/client-go v0.28.1/go.mod h1:pEZA3FqOsVkCc07pFVzK076R+P/eXqsgx5zuuRWukNE= k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/advisor/main.go b/advisor/main.go old mode 100644 new mode 100755 diff --git a/advisor/pkg/api/pod_traffic.go b/advisor/pkg/api/pod_traffic.go new file mode 100644 index 000000000..a1b83826c --- /dev/null +++ b/advisor/pkg/api/pod_traffic.go @@ -0,0 +1,135 @@ +package api + +import ( + "encoding/json" + "fmt" + "io/ioutil" + + "net/http" + "time" + + v1 "k8s.io/api/core/v1" + v1beta1 "k8s.io/api/discovery/v1beta1" +) + +type PodTraffic struct { + UUID string `yaml:"uuid" json:"uuid"` + SrcPodName string `yaml:"pod_name" json:"pod_name"` + SrcIP string `yaml:"pod_ip" json:"pod_ip"` + SrcNamespace string `yaml:"pod_namespace" json:"pod_namespace"` + SrcPodPort string `yaml:"pod_port" json:"pod_port"` + TrafficType string `yaml:"traffic_type" json:"traffic_type"` + DstIP string `yaml:"traffic_in_out_ip" json:"traffic_in_out_ip"` + DstPort string `yaml:"traffic_in_out_port" json:"traffic_in_out_port"` + Protocol v1.Protocol `yaml:"ip_protocol" json:"ip_protocol"` +} + +type PodDetail struct { + UUID string `yaml:"uuid" json:"uuid"` + PodIP string `yaml:"pod_ip" json:"pod_ip"` + Name string `yaml:"pod_name" json:"pod_name"` + Namespace string `yaml:"pod_namespace" json:"pod_namespace"` + Pod v1.Pod `yaml:"pod_obj" json:"pod_obj"` +} + +type SvcDetail struct { + SvcIp string `yaml:"svc_ip" json:"svc_ip"` + SvcName string `yaml:"svc_name" json:"svc_name"` + SvcNamespace string `yaml:"svc_namespace" json:"svc_namespace"` + EndPointSlice v1beta1.EndpointSlice `yaml:"endpoint_spec" json:"endpoint_spec"` +} + +func GetPodTraffic(podName string) ([]PodTraffic, error) { + + time.Sleep(3 * time.Second) + // Specify the URL of the REST API endpoint you want to invoke. + apiURL := "http://127.0.0.1:9090/podtraffic/pod/" + podName + + // Send an HTTP GET request to the API endpoint. + resp, err := http.Get(apiURL) + if err != nil { + fmt.Printf("Error making GET request: %v\n", err) + return nil, err + } + defer resp.Body.Close() + + // Check the HTTP status code. + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("received non-OK HTTP status code: %v", resp.StatusCode) + } + + var podTraffic []PodTraffic + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Println("Error reading response body:", err) + return nil, err + } + + // Parse the JSON response and unmarshal it into the Go struct. + if err := json.Unmarshal([]byte(body), &podTraffic); err != nil { + fmt.Printf("Error decoding JSON: %v\n", err) + return nil, err + } + + return podTraffic, nil +} + +// Should we just get the pod spec directly from the cluster and only use the DB for the SaaS version where it contains the pod spec? Would this help with reducing unnecessary chatter?And just let the client do it? +func GetPodSpec(ip string) (*PodDetail, error) { + + // Specify the URL of the REST API endpoint you want to invoke. + apiURL := "http://127.0.0.1:9090/netpol/pod/" + ip + + // Send an HTTP GET request to the API endpoint. + resp, err := http.Get(apiURL) + if err != nil { + fmt.Printf("Error making GET request: %v\n", err) + return nil, err + } + defer resp.Body.Close() + + // Check the HTTP status code. + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("received non-OK HTTP status code: %v", resp.StatusCode) + } + + var podDetails PodDetail + + // Parse the JSON response and unmarshal it into the Go struct. + if err := json.NewDecoder(resp.Body).Decode(&podDetails); err != nil { + fmt.Printf("Error decoding JSON: %v\n", err) + return nil, err + } + + return &podDetails, nil +} + +func GetSvcSpec(svcIp string) (*SvcDetail, error) { + + // Specify the URL of the RESTAPI endpoint you want to invoke. + apiURL := "http://127.0.0.1:9090//netpol/svc/" + svcIp + + // Send an HTTP GET request to the API endpoint. + resp, err := http.Get(apiURL) + if err != nil { + fmt.Printf("Error making GET request: %v\n", err) + return nil, err + } + defer resp.Body.Close() + + // Check the HTTP status code. + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("received non-OK HTTP status code: %v", resp.StatusCode) + } + + var svcDetail SvcDetail + + // Parse the JSON response and unmarshal it into the Go struct. + if err := json.NewDecoder(resp.Body).Decode(&svcDetail); err != nil { + fmt.Printf("Error decoding JSON: %v\n", err) + return nil, err + } + + return &svcDetail, nil +} diff --git a/advisor/pkg/database/db.go b/advisor/pkg/database/db.go deleted file mode 100644 index 7718c6e27..000000000 --- a/advisor/pkg/database/db.go +++ /dev/null @@ -1,119 +0,0 @@ -package db - -import ( - "database/sql" - "fmt" - - _ "github.com/lib/pq" -) - -type PodTraffic struct { - UUID string - SrcPodName string - SrcIP string - SrcNamespace string - DstPodName string - DstIP string - DstNamespace string - TimeStamp string -} - -type PodSpec struct { - UUID string - Name string - Namespace string - Spec map[string]interface{} -} - -type DBConnection struct { - db *sql.DB -} - -type PodTrafficGetter interface { - GetPodTraffic(uuid string) (*PodTraffic, error) - GetPodSpec(name string) (*PodSpec, error) -} - -type PodTrafficStub struct{} - -func NewDBConnection(host string, port int, user string, password string, dbname string) (*DBConnection, error) { - psqlInfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", - host, port, user, password, dbname) - - db, err := sql.Open("postgres", psqlInfo) - if err != nil { - return nil, err - } - - err = db.Ping() - if err != nil { - return nil, err - } - - return &DBConnection{db: db}, nil -} - -func (dbc *DBConnection) Close() error { - return dbc.db.Close() -} - -func (dbc *DBConnection) GetPodTraffic(podName string) (*PodTraffic, error) { - row := dbc.db.QueryRow("SELECT * FROM pod_traffic WHERE pod_name = $1", podName) - - podTraffic := new(PodTraffic) - err := row.Scan(&podTraffic.UUID, &podTraffic.SrcPodName, &podTraffic.SrcIP, &podTraffic.SrcNamespace, - &podTraffic.DstPodName, &podTraffic.DstIP, &podTraffic.DstNamespace, &podTraffic.TimeStamp) - if err != nil { - if err == sql.ErrNoRows { - // There were no rows, but otherwise no error occurred - return nil, nil - } - return nil, err - } - - return podTraffic, nil -} - -func (dbc *DBConnection) GetPodSpec(name string) (*PodSpec, error) { - row := dbc.db.QueryRow("SELECT * FROM pod_spec WHERE name = $1", name) - - podSpec := new(PodSpec) - err := row.Scan(&podSpec.UUID, &podSpec.Name, &podSpec.Namespace) - if err != nil { - if err == sql.ErrNoRows { - // There were no rows, but otherwise no error occurred - return nil, nil - } - return nil, err - } - - // You may need a separate query to get the 'spec' column, depending on its type in the database - // For this example, I'm leaving it as an empty map - podSpec.Spec = make(map[string]interface{}) - - return podSpec, nil -} - -func (pts *PodTrafficStub) GetPodTraffic(podName string) (*PodTraffic, error) { - // Return dummy data, or whatever is appropriate for your use case - return &PodTraffic{ - UUID: "example-uuid", - SrcPodName: podName, - SrcIP: "0.0.0.0", - SrcNamespace: "default", - DstPodName: "dummy-dst-pod", - DstIP: "0.0.0.0", - DstNamespace: "default", - TimeStamp: "2023-07-15T15:04:05Z", - }, nil -} - -func (pts *PodTrafficStub) GetPodSpec(name string) (*PodSpec, error) { - // Return dummy data, or whatever is appropriate for your use case - return &PodSpec{ - UUID: "dummy-uuid", - Name: name, - Namespace: "default", - Spec: make(map[string]interface{}), - }, nil -} diff --git a/advisor/pkg/k8s/auth.go b/advisor/pkg/k8s/auth.go new file mode 100644 index 000000000..773ddc5cc --- /dev/null +++ b/advisor/pkg/k8s/auth.go @@ -0,0 +1,71 @@ +package k8s + +import ( + "fmt" + "os" + "path/filepath" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" +) + +// Config stores Kubernetes client and other flag-based configurations +type Config struct { + Clientset *kubernetes.Clientset + Kubeconfig string + Namespace string + Config *rest.Config +} + +// NewConfig returns a new Config struct initialized with a Kubernetes client +func NewConfig(kubeconfig string, namespace string) (*Config, error) { + // If kubeconfig flag is not set, fallback to environment variable + if kubeconfig == "" { + kubeconfig = os.Getenv("KUBECONFIG") + } + + // If neither flag nor environment variable is set, fallback to default path + if kubeconfig == "" { + home, err := os.UserHomeDir() + if err != nil { + fmt.Println("Unable to get user home directory: ", err) + os.Exit(1) + } + kubeconfig = filepath.Join(home, ".kube", "config") + } + + currentConfig, err := clientcmd.LoadFromFile(kubeconfig) + if err != nil { + fmt.Printf("Error reading kubeconfig: %v\n", err) + return nil, err + } + + // If namespace flag is not set, fallback to current context + if namespace == "" { + if context, ok := currentConfig.Contexts[currentConfig.CurrentContext]; ok { + namespace = context.Namespace + // If namespace flag is not set, and no current context, fallback to default namespace + if namespace == "" { + namespace = "default" + } + } + } + + config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + return nil, err + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, err + } + + return &Config{ + Clientset: clientset, + Kubeconfig: kubeconfig, + Namespace: namespace, + Config: config, + }, nil +} diff --git a/advisor/pkg/k8s/networkpolicies.go b/advisor/pkg/k8s/networkpolicies.go index 851aaf9db..47307273e 100644 --- a/advisor/pkg/k8s/networkpolicies.go +++ b/advisor/pkg/k8s/networkpolicies.go @@ -4,27 +4,13 @@ import ( "fmt" "log" - db "github.com/arx-inc/advisor/pkg/database" - v1 "k8s.io/api/core/v1" + api "github.com/arx-inc/advisor/pkg/api" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/yaml" ) -const ( - // TODO: Remove these hardcoded values - name = "test-network-policy" - namespace = "default" - - // TODO: replace these with your actual PostgreSQL connection details - host = "localhost" - port = 5432 - user = "youruser" - password = "yourpassword" - dbname = "yourdb" -) - type NetworkPolicyRule struct { Ports []networkingv1.NetworkPolicyPort FromTo []networkingv1.NetworkPolicyPeer @@ -37,94 +23,36 @@ type NetworkPolicySpec struct { Egress []NetworkPolicyRule } -func GenerateNetworkPolicy(podName string) { - // Decide whether to use real DB or stub - var podTrafficGetter db.PodTrafficGetter - useDB := false // change this to false to use the stub +type RuleSets struct { + Ingress []networkingv1.NetworkPolicyIngressRule + Egress []networkingv1.NetworkPolicyEgressRule +} - if useDB { - var err error - podTrafficGetter, err = db.NewDBConnection(host, port, user, password, dbname) - if err != nil { - log.Fatalf("Error opening database connection: %v\n", err) - return - } - defer podTrafficGetter.(*db.DBConnection).Close() - } else { - podTrafficGetter = &db.PodTrafficStub{} - } +func GenerateNetworkPolicy(podName, namespace string) { - // example of querying for a specific UUID - podTraffic, err := podTrafficGetter.GetPodTraffic(podName) + podTraffic, err := api.GetPodTraffic(podName) if err != nil { log.Fatalf("Error retrieving pod traffic: %v\n", err) return } - if podTraffic != nil { - fmt.Printf("Pod traffic for pod %s: %+v\n", podName, podTraffic) - } else { + if podTraffic == nil { fmt.Printf("No pod traffic found for pod %s\n", podName) + return } - podSpec, err := podTrafficGetter.GetPodSpec(podTraffic.SrcPodName) + podDetail, err := api.GetPodSpec(podTraffic[0].SrcIP) if err != nil { log.Fatalf("Error retrieving pod spec: %v\n", err) return } - if podSpec != nil { - fmt.Printf("Pod spec for pod %s: %+v\n", podSpec.Name, podSpec.Spec) - } else { - fmt.Printf("No pod spec found for pod %s\n", podSpec) - } - - // TODO: replace this with your actual network policy spec from the database - spec := NetworkPolicySpec{ - PodSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "app": "MyApp", - }, - }, - PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress, networkingv1.PolicyTypeEgress}, - Ingress: []NetworkPolicyRule{ - { - Ports: []networkingv1.NetworkPolicyPort{ - { - Protocol: protoPtr(v1.ProtocolTCP), - Port: intStrPtr(8080), - }, - }, - FromTo: []networkingv1.NetworkPolicyPeer{ - { - PodSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "access": "allowed", - }, - }, - NamespaceSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "kubernetes.io/metadata.name:": "some-namespace", - }, - }, - }, - }, - }, - }, - Egress: []NetworkPolicyRule{ - { - // No ports specified, so all ports are allowed - Ports: []networkingv1.NetworkPolicyPort{}, - FromTo: []networkingv1.NetworkPolicyPeer{ - { - // No pod selector or namespace selector specified, so all destinations are allowed - }, - }, - }, - }, + if podDetail == nil { + fmt.Printf("No pod spec found for pod %s\n", podDetail.Name) + return } - policy := CreateNetworkPolicy(name, namespace, spec) + policy := TransformToNetworkPolicy(&podTraffic, podDetail) policyYAML, err := yaml.Marshal(policy) if err != nil { fmt.Printf("Error converting policy to YAML: %v", err) @@ -134,43 +62,79 @@ func GenerateNetworkPolicy(podName string) { fmt.Println(string(policyYAML)) } -func CreateNetworkPolicy(name, namespace string, spec NetworkPolicySpec) *networkingv1.NetworkPolicy { +func TransformToNetworkPolicy(podTraffic *[]api.PodTraffic, podDetail *api.PodDetail) *networkingv1.NetworkPolicy { + var ingressRules []networkingv1.NetworkPolicyIngressRule + var egressRules []networkingv1.NetworkPolicyEgressRule + + for _, traffic := range *podTraffic { + + // Get pod spec for the pod that is sending traffic + origin, err := api.GetPodSpec(traffic.DstIP) + if err != nil { + // TODO: Handle errors, for now just continue as this is not a fatal error and it assumes the traffic originated from outside the cluster + continue + } + + port := intstr.Parse(traffic.SrcPodPort) + networkPolicyPort := networkingv1.NetworkPolicyPort{ + Protocol: &traffic.Protocol, + Port: &port, + } + + peer := networkingv1.NetworkPolicyPeer{} + // If the traffic originated from in-cluster as either a pod or service + if origin != nil { + peer = networkingv1.NetworkPolicyPeer{ + PodSelector: &metav1.LabelSelector{ + // TODO: Check if this is the correct label to use + MatchLabels: map[string]string{"app.kubernetes.io/name": origin.Pod.ObjectMeta.Labels["app.kubernetes.io/name"]}, + }, + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"kubernetes.io/metadata.name": origin.Pod.ObjectMeta.Namespace}, + }, + } + } + + if traffic.TrafficType == "INGRESS" { + ingressRules = append(ingressRules, networkingv1.NetworkPolicyIngressRule{ + Ports: []networkingv1.NetworkPolicyPort{networkPolicyPort}, + From: []networkingv1.NetworkPolicyPeer{peer}, + }) + } else if traffic.TrafficType == "EGRESS" { + egressRules = append(egressRules, networkingv1.NetworkPolicyEgressRule{ + Ports: []networkingv1.NetworkPolicyPort{networkPolicyPort}, + To: []networkingv1.NetworkPolicyPeer{peer}, + }) + } + } + networkPolicy := &networkingv1.NetworkPolicy{ TypeMeta: metav1.TypeMeta{ APIVersion: "networking.k8s.io/v1", Kind: "NetworkPolicy", }, ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, + Name: podDetail.Name, + Namespace: podDetail.Namespace, + // TODO: What labels should we use? + Labels: map[string]string{ + "advisor.arx.io/managed-by": "arx", + "advisor.arx.io/version": "0.0.1", + }, }, Spec: networkingv1.NetworkPolicySpec{ - PodSelector: spec.PodSelector, - PolicyTypes: spec.PolicyTypes, + PodSelector: metav1.LabelSelector{ + // TODO: Check if this is the correct label to use + MatchLabels: map[string]string{"app.kubernetes.io/name": podDetail.Pod.ObjectMeta.Labels["app.kubernetes.io/name"]}, + }, + PolicyTypes: []networkingv1.PolicyType{ + networkingv1.PolicyTypeIngress, + networkingv1.PolicyTypeEgress, + }, + Ingress: ingressRules, + Egress: egressRules, }, } - for _, rule := range spec.Ingress { - networkPolicy.Spec.Ingress = append(networkPolicy.Spec.Ingress, networkingv1.NetworkPolicyIngressRule{ - Ports: rule.Ports, - From: rule.FromTo, - }) - } - - for _, rule := range spec.Egress { - networkPolicy.Spec.Egress = append(networkPolicy.Spec.Egress, networkingv1.NetworkPolicyEgressRule{ - Ports: rule.Ports, - To: rule.FromTo, - }) - } - return networkPolicy } - -func protoPtr(protocol v1.Protocol) *v1.Protocol { - return &protocol -} - -func intStrPtr(port int32) *intstr.IntOrString { - return &intstr.IntOrString{IntVal: port} -} diff --git a/advisor/pkg/k8s/portforward.go b/advisor/pkg/k8s/portforward.go new file mode 100644 index 000000000..d6f54301e --- /dev/null +++ b/advisor/pkg/k8s/portforward.go @@ -0,0 +1,72 @@ +package k8s + +import ( + "context" + "io/ioutil" + "net/http" + "os" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/portforward" + "k8s.io/client-go/transport/spdy" +) + +var ( + serviceNamespace = "kube-guardian" + serviceName = "kubeguardian-api" + ports = []string{"9090:9090"} +) + +// PortForward sets up a port-forwarding from the local machine to the given pod. +// It runs the port-forwarding operation in a Goroutine and returns a channel to stop the port-forwarding +func PortForward(config *Config) (chan struct{}, chan error, chan bool) { + stopChan := make(chan struct{}, 1) + errChan := make(chan error, 1) + done := make(chan bool) + + go func() { + service, err := config.Clientset.CoreV1().Services(serviceNamespace).Get(context.TODO(), serviceName, metav1.GetOptions{}) + if err != nil { + errChan <- err + return + } + + pods, err := config.Clientset.CoreV1().Pods(serviceNamespace).List(context.TODO(), metav1.ListOptions{LabelSelector: service.Spec.Selector["app"]}) + if err != nil { + errChan <- err + return + } + + // Use the first pod in the pods list and return its metadata + pod := pods.Items[0].ObjectMeta + + // Set up Port Forwarding + url := config.Clientset.CoreV1().RESTClient().Post(). + Resource("pods"). + Namespace(pod.Namespace). + Name(pod.Name). + SubResource("portforward").URL() + + transport, upgrader, err := spdy.RoundTripperFor(config.Config) + if err != nil { + errChan <- err + return + } + + dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", url) + + pf, err := portforward.New(dialer, ports, make(chan struct{}, 1), make(chan struct{}, 1), ioutil.Discard, os.Stderr) + if err != nil { + errChan <- err + return + } + done <- true // Signal that the goroutine is done + if err := pf.ForwardPorts(); err != nil { + errChan <- err + return + } + + }() + + return stopChan, errChan, done +} From e091886195818a2ca90e72411b7b9b5e8b9a4f1b Mon Sep 17 00:00:00 2001 From: Michael Fornaro <20387402+xUnholy@users.noreply.github.com> Date: Fri, 15 Sep 2023 14:48:47 +1000 Subject: [PATCH 4/4] feat: push changes relating to label selectors Signed-off-by: Michael Fornaro <20387402+xUnholy@users.noreply.github.com> --- README.md | 4 +-- advisor/README.md | 52 +++++++++++++++++---------- advisor/cmd/gen.go | 2 +- advisor/pkg/k8s/labels.go | 56 +++++++++++++++++++++++++++++ advisor/pkg/k8s/networkpolicies.go | 57 +++++++++++++++++++++--------- 5 files changed, 133 insertions(+), 38 deletions(-) create mode 100644 advisor/pkg/k8s/labels.go diff --git a/README.md b/README.md index 6abda3649..6bcf59720 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,13 @@ mv arx /usr/local/bin/ ### 🔒 Generate Network Policies ```bash -kubectl arx gen networkpolicy [pod-name] --namespace my-namespace +kubectl arx gen networkpolicy [pod-name] --namespace [namespace-name] ``` ### 🛡️ Generate Seccomp Profiles ```bash -kubectl arx gen seccomp [pod-name] --namespace my-namespace +kubectl arx gen seccomp [pod-name] --namespace [namespace-name] ``` For more details on the commands: diff --git a/advisor/README.md b/advisor/README.md index c7881b245..e66f6a3c2 100644 --- a/advisor/README.md +++ b/advisor/README.md @@ -1,24 +1,6 @@ Sudo Filter Logic ================= -type PodTraffic struct { - UUID string - SrcPodName string - SrcIP string - SrcNamespace string - DstPodName string - DstIP string - DstNamespace string - TimeStamp string -} - -type PodSpec struct { - UUID string - Name string - Namespace string - Spec map[string]interface{} -} - For Pod get all the traffic relating to it Get the PodSpec for the Pod Iterate all Ingress for each Source Pod @@ -39,3 +21,37 @@ Day 2? - Potentially split ingress and egress into separate policies? - Support CIDR ranges and external to cluster traffic - All protocol types + + + + + + + + +NetPol + +type PodTraffic struct { + UUID string `yaml:"uuid" json:"uuid"` + SrcPodName string `yaml:"pod_name" json:"pod_name"` + SrcIP string `yaml:"pod_ip" json:"pod_ip"` + SrcNamespace string `yaml:"pod_namespace" json:"pod_namespace"` + SrcPodPort string `yaml:"pod_port" json:"pod_port"` + TrafficType string `yaml:"traffic_type" json:"traffic_type"` + DstIP string `yaml:"traffic_in_out_ip" json:"traffic_in_out_ip"` + DstPort string `yaml:"traffic_in_out_port" json:"traffic_in_out_port"` + Protocol v1.Protocol `yaml:"ip_protocol" json:"ip_protocol"` +} + +type PodDetail struct { + UUID string `yaml:"uuid" json:"uuid"` + PodIP string `yaml:"pod_ip" json:"pod_ip"` + Name string `yaml:"pod_name" json:"pod_name"` + Namespace string `yaml:"pod_namespace" json:"pod_namespace"` + Pod v1.Pod `yaml:"pod_obj" json:"pod_obj"` +} + + +When [POD] receives INGRESS the network policy for INGRESS should use DstIP to get the PodDetails for that PodIP. The SrcPodPort is the port the INGRESS traffic came through. + +When [POD] receives EGRESS the network policy for EGRESS should use DstIP to get the PodDetails for that PodIP. The DstPort is the port the EGRESS traffic left through. diff --git a/advisor/cmd/gen.go b/advisor/cmd/gen.go index 02f6db65e..a9f7c23ee 100644 --- a/advisor/cmd/gen.go +++ b/advisor/cmd/gen.go @@ -43,7 +43,7 @@ var networkPolicyCmd = &cobra.Command{ } }() fmt.Println("Port forwarding set up successfully.") - k8s.GenerateNetworkPolicy(podName, config.Namespace) + k8s.GenerateNetworkPolicy(podName, config) close(stopChan) }, } diff --git a/advisor/pkg/k8s/labels.go b/advisor/pkg/k8s/labels.go new file mode 100644 index 000000000..b61bf506e --- /dev/null +++ b/advisor/pkg/k8s/labels.go @@ -0,0 +1,56 @@ +package k8s + +import ( + "context" + "fmt" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// DetectLabels detects the labels of a pod. +func DetectSelectorLabels(clientset *kubernetes.Clientset, pod *v1.Pod) (map[string]string, error) { + ctx := context.TODO() + + // Check if the Pod has an owner + if len(pod.OwnerReferences) > 0 { + owner := pod.OwnerReferences[0] + + // Based on the owner, get the controller object to check its labels + switch owner.Kind { + case "ReplicaSet": + replicaSet, err := clientset.AppsV1().ReplicaSets(pod.Namespace).Get(ctx, owner.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + deployment, err := clientset.AppsV1().Deployments(pod.Namespace).Get(ctx, replicaSet.OwnerReferences[0].Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return deployment.Spec.Selector.MatchLabels, nil + + case "StatefulSet": + statefulSet, err := clientset.AppsV1().StatefulSets(pod.Namespace).Get(ctx, owner.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return statefulSet.Spec.Selector.MatchLabels, nil + + case "DaemonSet": + daemonSet, err := clientset.AppsV1().DaemonSets(pod.Namespace).Get(ctx, owner.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return daemonSet.Spec.Selector.MatchLabels, nil + + // Add more controller kinds here if needed + + default: + return nil, fmt.Errorf("unknown or unsupported owner kind: %s", owner.Kind) + } + } + + // If we reach here, the Pod has no owner and we return its own labels + return pod.Labels, nil +} diff --git a/advisor/pkg/k8s/networkpolicies.go b/advisor/pkg/k8s/networkpolicies.go index 47307273e..5a6674942 100644 --- a/advisor/pkg/k8s/networkpolicies.go +++ b/advisor/pkg/k8s/networkpolicies.go @@ -28,7 +28,7 @@ type RuleSets struct { Egress []networkingv1.NetworkPolicyEgressRule } -func GenerateNetworkPolicy(podName, namespace string) { +func GenerateNetworkPolicy(podName string, config *Config) { podTraffic, err := api.GetPodTraffic(podName) if err != nil { @@ -37,7 +37,7 @@ func GenerateNetworkPolicy(podName, namespace string) { } if podTraffic == nil { - fmt.Printf("No pod traffic found for pod %s\n", podName) + log.Fatalf("No pod traffic found for pod %s\n", podName) return } @@ -48,11 +48,11 @@ func GenerateNetworkPolicy(podName, namespace string) { } if podDetail == nil { - fmt.Printf("No pod spec found for pod %s\n", podDetail.Name) + log.Fatalf("No pod spec found for pod %s\n", podDetail.Name) return } - policy := TransformToNetworkPolicy(&podTraffic, podDetail) + policy := TransformToNetworkPolicy(&podTraffic, podDetail, config) policyYAML, err := yaml.Marshal(policy) if err != nil { fmt.Printf("Error converting policy to YAML: %v", err) @@ -62,23 +62,36 @@ func GenerateNetworkPolicy(podName, namespace string) { fmt.Println(string(policyYAML)) } -func TransformToNetworkPolicy(podTraffic *[]api.PodTraffic, podDetail *api.PodDetail) *networkingv1.NetworkPolicy { +func TransformToNetworkPolicy(podTraffic *[]api.PodTraffic, podDetail *api.PodDetail, config *Config) *networkingv1.NetworkPolicy { var ingressRules []networkingv1.NetworkPolicyIngressRule var egressRules []networkingv1.NetworkPolicyEgressRule + // TODO: How to perform this action offline + podSelectorLabels, err := DetectSelectorLabels(config.Clientset, &podDetail.Pod) + if err != nil { + fmt.Println(err) + // TODO: Handle errors, this would mean a controller was detected but may no longer exist due to the pod being deleted but still present in the database + fmt.Println("Detect Labels of pod", err) + return nil + } + for _, traffic := range *podTraffic { + // TODO: Check PODCIDR and SVCCIDR to determine if IP originated from inside or outside the cluster + // Get pod spec for the pod that is sending traffic origin, err := api.GetPodSpec(traffic.DstIP) if err != nil { // TODO: Handle errors, for now just continue as this is not a fatal error and it assumes the traffic originated from outside the cluster + fmt.Println("Get Pod Spec of origin", traffic.DstIP, err) continue } - port := intstr.Parse(traffic.SrcPodPort) - networkPolicyPort := networkingv1.NetworkPolicyPort{ - Protocol: &traffic.Protocol, - Port: &port, + peerSelectorLabels, err := DetectSelectorLabels(config.Clientset, &origin.Pod) + if err != nil { + // TODO: Handle errors, this would mean a controller was detected but may no longer exist due to the pod being deleted but still present in the database + fmt.Println("Detect Labels", origin.Name, err) + continue } peer := networkingv1.NetworkPolicyPeer{} @@ -86,8 +99,7 @@ func TransformToNetworkPolicy(podTraffic *[]api.PodTraffic, podDetail *api.PodDe if origin != nil { peer = networkingv1.NetworkPolicyPeer{ PodSelector: &metav1.LabelSelector{ - // TODO: Check if this is the correct label to use - MatchLabels: map[string]string{"app.kubernetes.io/name": origin.Pod.ObjectMeta.Labels["app.kubernetes.io/name"]}, + MatchLabels: peerSelectorLabels, }, NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"kubernetes.io/metadata.name": origin.Pod.ObjectMeta.Namespace}, @@ -96,14 +108,26 @@ func TransformToNetworkPolicy(podTraffic *[]api.PodTraffic, podDetail *api.PodDe } if traffic.TrafficType == "INGRESS" { + port := intstr.Parse(traffic.SrcPodPort) ingressRules = append(ingressRules, networkingv1.NetworkPolicyIngressRule{ - Ports: []networkingv1.NetworkPolicyPort{networkPolicyPort}, - From: []networkingv1.NetworkPolicyPeer{peer}, + Ports: []networkingv1.NetworkPolicyPort{ + { + Protocol: &traffic.Protocol, + Port: &port, + }, + }, + From: []networkingv1.NetworkPolicyPeer{peer}, }) } else if traffic.TrafficType == "EGRESS" { + port := intstr.Parse(traffic.DstPort) egressRules = append(egressRules, networkingv1.NetworkPolicyEgressRule{ - Ports: []networkingv1.NetworkPolicyPort{networkPolicyPort}, - To: []networkingv1.NetworkPolicyPeer{peer}, + Ports: []networkingv1.NetworkPolicyPort{ + { + Protocol: &traffic.Protocol, + Port: &port, + }, + }, + To: []networkingv1.NetworkPolicyPeer{peer}, }) } } @@ -124,8 +148,7 @@ func TransformToNetworkPolicy(podTraffic *[]api.PodTraffic, podDetail *api.PodDe }, Spec: networkingv1.NetworkPolicySpec{ PodSelector: metav1.LabelSelector{ - // TODO: Check if this is the correct label to use - MatchLabels: map[string]string{"app.kubernetes.io/name": podDetail.Pod.ObjectMeta.Labels["app.kubernetes.io/name"]}, + MatchLabels: podSelectorLabels, }, PolicyTypes: []networkingv1.PolicyType{ networkingv1.PolicyTypeIngress,