Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: Daichi Sakaue <[email protected]>
  • Loading branch information
yokaze committed Oct 17, 2024
1 parent a5f5537 commit 65015ce
Show file tree
Hide file tree
Showing 21 changed files with 925 additions and 41 deletions.
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Build the manager binary
FROM ghcr.io/cybozu/golang:1.23-jammy AS builder

# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY cmd/cilium-agent-proxy/ cmd/cilium-agent-proxy/

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o cilium-agent-proxy ./cmd/cilium-agent-proxy

# Compose the manager container
FROM ghcr.io/cybozu/ubuntu:22.04
LABEL org.opencontainers.image.source=https://github.com/cybozu-go/network-policy-viewer

WORKDIR /
COPY --from=builder /work/cilium-agent-proxy /

USER 10000:10000
ENTRYPOINT ["/cilium-agent-proxy"]
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ clean:
.PHONY: build
build: ## Build network-policy-viewer
mkdir -p $(BIN_DIR)
go build -trimpath -ldflags "-w -s" -o $(BIN_DIR)/npv main.go
go build -trimpath -ldflags "-w -s" -o $(BIN_DIR)/npv ./cmd/npv

.PHONY: check-generate
check-generate:
Expand Down
7 changes: 7 additions & 0 deletions cmd/cilium-agent-proxy/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "github.com/cybozu-go/network-policy-viewer/cmd/cilium-agent-proxy/sub"

func main() {
sub.Execute()
}
28 changes: 28 additions & 0 deletions cmd/cilium-agent-proxy/sub/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package sub

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "cilium-agent-proxy",
Short: "cilium-agent proxy",
Long: `cilium-agent proxy`,

RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
return subMain()
},
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
109 changes: 109 additions & 0 deletions cmd/cilium-agent-proxy/sub/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package sub

import (
"context"
"fmt"
"io"
"net"
"net/http"
"regexp"
"strconv"
)

const socketPath = "/var/run/cilium/cilium.sock"

var (
endpointPattern *regexp.Regexp
identityPattern *regexp.Regexp
)

func handleEndpoint(w http.ResponseWriter, r *http.Request) {
match := endpointPattern.FindStringSubmatch(r.URL.Path)
if match == nil || len(match) < 2 {
fmt.Fprint(w, "error\n")
return
}
client := http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", socketPath)
},
},
}

// Convert to number to avoid possible parameter injection
endpoint, err := strconv.Atoi(match[1])
if err != nil {
fmt.Fprint(w, "error\n")
return
}

url := fmt.Sprintf("http://localhost/v1/endpoint/%d", endpoint)
resp, err := client.Get(url)
if err != nil {
fmt.Fprint(w, "error\n")
return
}

io.Copy(w, resp.Body)
}

func handleIdentity(w http.ResponseWriter, r *http.Request) {
match := identityPattern.FindStringSubmatch(r.URL.Path)
if match == nil || len(match) < 2 {
fmt.Fprint(w, "error\n")
return
}
client := http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", socketPath)
},
},
}

// Convert to number to avoid possible parameter injection
identity, err := strconv.Atoi(match[1])
if err != nil {
fmt.Fprint(w, "error\n")
return
}

url := fmt.Sprintf("http://localhost/v1/identity/%d", identity)
resp, err := client.Get(url)
if err != nil {
fmt.Fprint(w, "error\n")
return
}

io.Copy(w, resp.Body)
}

func handlePolicy(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "policy")
}

func subMain() error {
pattern, err := regexp.Compile(`^/endpoint/(?P<endpoint>\d+)$`)
endpointPattern = pattern
if err != nil {
return err
}

pattern, err = regexp.Compile(`^/identity/(?P<identity>\d+)$`)
identityPattern = pattern
if err != nil {
return err
}

server := http.Server{
Addr: ":8080",
Handler: nil,
}

http.HandleFunc("/endpoint/", handleEndpoint)
http.HandleFunc("/identity/", handleIdentity)
http.HandleFunc("/policy/", handlePolicy)

return server.ListenAndServe()
}
2 changes: 1 addition & 1 deletion cmd/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func runDump(ctx context.Context, w io.Writer, name string) error {
return err
}

endpointID, err := getPodEndpointID(ctx, dynamicClient, rootOptions.namespace, name)
endpointID, _, err := getPodEndpointID(ctx, dynamicClient, rootOptions.namespace, name)
if err != nil {
return err
}
Expand Down
66 changes: 54 additions & 12 deletions cmd/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"strconv"

"github.com/cilium/cilium/pkg/client"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -14,13 +15,17 @@ import (
"k8s.io/client-go/rest"
)

const (
directionEgress = "EGRESS"
directionIngress = "INGRESS"
)

func createClients(ctx context.Context, name string) (*kubernetes.Clientset, *dynamic.DynamicClient, *client.Client, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, nil, nil, err
}

// Create Kubernetes Clients
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, nil, nil, err
Expand All @@ -31,19 +36,26 @@ func createClients(ctx context.Context, name string) (*kubernetes.Clientset, *dy
return nil, nil, nil, err
}

// Create Cilium Client
endpoint, err := getProxyEndpoint(ctx, clientset, rootOptions.namespace, name)
if err != nil {
return nil, nil, nil, err
}
ciliumClient, err := client.NewClient(endpoint)
ciliumClient, err := createCiliumClient(ctx, clientset, rootOptions.namespace, name)
if err != nil {
return nil, nil, nil, err
}

return clientset, dynamicClient, ciliumClient, err
}

func createCiliumClient(ctx context.Context, clientset *kubernetes.Clientset, namespace, name string) (*client.Client, error) {
endpoint, err := getProxyEndpoint(ctx, clientset, namespace, name)
if err != nil {
return nil, err
}
client, err := client.NewClient(endpoint)
if err != nil {
return nil, err
}
return client, nil
}

func getProxyEndpoint(ctx context.Context, c *kubernetes.Clientset, namespace, name string) (string, error) {
targetPod, err := c.CoreV1().Pods(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
Expand All @@ -67,7 +79,7 @@ func getProxyEndpoint(ctx context.Context, c *kubernetes.Clientset, namespace, n
return fmt.Sprintf("http://%s:%d", podIP, rootOptions.proxyPort), nil
}

func getPodEndpointID(ctx context.Context, d *dynamic.DynamicClient, namespace, name string) (int64, error) {
func getPodEndpointID(ctx context.Context, d *dynamic.DynamicClient, namespace, name string) (int64, int64, error) {
gvr := schema.GroupVersionResource{
Group: "cilium.io",
Version: "v2",
Expand All @@ -76,16 +88,46 @@ func getPodEndpointID(ctx context.Context, d *dynamic.DynamicClient, namespace,

ep, err := d.Resource(gvr).Namespace(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return 0, err
return 0, 0, err
}

endpointID, found, err := unstructured.NestedInt64(ep.Object, "status", "id")
if err != nil {
return 0, err
return 0, 0, err
}
if !found {
return 0, 0, errors.New("CiliumEndpoint does not have .status.id")
}

endpointIdentity, found, err := unstructured.NestedInt64(ep.Object, "status", "identity", "id")
if err != nil {
return 0, 0, err
}
if !found {
return 0, errors.New("endpoint resource is broken")
return 0, 0, errors.New("CiliumEndpoint does not have .status.identity.id")
}

return endpointID, nil
return endpointID, endpointIdentity, nil
}

func listCiliumIDs(ctx context.Context, d *dynamic.DynamicClient) (*unstructured.UnstructuredList, error) {
gvr := schema.GroupVersionResource{
Group: "cilium.io",
Version: "v2",
Resource: "ciliumidentities",
}
return d.Resource(gvr).List(ctx, metav1.ListOptions{})
}

func findCiliumID(dict *unstructured.UnstructuredList, id int64) *unstructured.Unstructured {
if dict == nil {
return nil
}
name := strconv.FormatInt(id, 10)
for _, item := range dict.Items {
if item.GetName() == name {
return &item
}
}
return nil
}
13 changes: 13 additions & 0 deletions cmd/l3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cmd

import "github.com/spf13/cobra"

var l3Cmd = &cobra.Command{
Use: "l3",
Short: "inspect l3 rules",
Long: `inspect l3 rules`,
}

func init() {
rootCmd.AddCommand(l3Cmd)
}
Loading

0 comments on commit 65015ce

Please sign in to comment.