diff --git a/Makefile b/Makefile index a57b38748..396e9a82c 100644 --- a/Makefile +++ b/Makefile @@ -10,10 +10,11 @@ COMMIT := $(shell git rev-parse --short HEAD) DATE := $(shell git log -1 --format=%cd --date=format:"%Y%m%d") BUILD_VERSION ?= $(shell git describe --match 'v[0-9]*' --dirty --always --tags) +BUILD_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) BUILD_ARCH := $(shell go env GOARCH) BUILD_OS := $(shell go env GOOS) -BUILD_FLAGS := -ldflags="-X github.com/DataDog/KubeHound/pkg/config.BuildVersion=$(BUILD_VERSION) -X github.com/DataDog/KubeHound/pkg/config.BuildArch=$(BUILD_ARCH) -X github.com/DataDog/KubeHound/pkg/config.BuildOs=$(BUILD_OS) -s -w" +BUILD_FLAGS := -ldflags="-X github.com/DataDog/KubeHound/pkg/config.BuildVersion=$(BUILD_VERSION) -X github.com/DataDog/KubeHound/pkg/config.BuildBranch=$(BUILD_BRANCH) -X github.com/DataDog/KubeHound/pkg/config.BuildArch=$(BUILD_ARCH) -X github.com/DataDog/KubeHound/pkg/config.BuildOs=$(BUILD_OS) -s -w" # Need to save the MAKEFILE_LIST variable before the including the env var files HELP_MAKEFILE_LIST := $(MAKEFILE_LIST) diff --git a/cmd/kubehound/backend.go b/cmd/kubehound/backend.go index 295743b8e..afb8349bd 100644 --- a/cmd/kubehound/backend.go +++ b/cmd/kubehound/backend.go @@ -1,6 +1,7 @@ package main import ( + "github.com/DataDog/KubeHound/pkg/backend" docker "github.com/DataDog/KubeHound/pkg/backend" "github.com/spf13/cobra" ) @@ -9,6 +10,9 @@ var ( Backend *docker.Backend hard bool composePath []string + + uiProfile = backend.DefaultUIProfile + uiInvana bool ) var ( @@ -17,7 +21,11 @@ var ( Short: "Handle the kubehound stack", Long: `Handle the kubehound stack - docker compose based stack for kubehound services (mongodb, graphdb and UI)`, PersistentPreRunE: func(cobraCmd *cobra.Command, args []string) error { - return docker.NewBackend(cobraCmd.Context(), composePath) + if uiInvana { + uiProfile = append(uiProfile, "invana") + } + + return docker.NewBackend(cobraCmd.Context(), composePath, uiProfile) }, } @@ -78,5 +86,6 @@ func init() { backendCmd.AddCommand(backendDownCmd) backendCmd.PersistentFlags().StringSliceVarP(&composePath, "file", "f", composePath, "Compose configuration files") + backendCmd.PersistentFlags().BoolVar(&uiInvana, "invana", false, "Activate Invana front end as KubeHound UI alternative") rootCmd.AddCommand(backendCmd) } diff --git a/cmd/kubehound/dev.go b/cmd/kubehound/dev.go index 4529d2258..21ba1f71c 100644 --- a/cmd/kubehound/dev.go +++ b/cmd/kubehound/dev.go @@ -4,15 +4,16 @@ import ( "context" "os" + "github.com/DataDog/KubeHound/pkg/backend" docker "github.com/DataDog/KubeHound/pkg/backend" "github.com/spf13/cobra" ) var ( DefaultComposeTestingPath = []string{"./deployments/kubehound/docker-compose.yaml", "./deployments/kubehound/docker-compose.testing.yaml"} - DefaultComposeDevPath = []string{"./deployments/kubehound/docker-compose.yaml", "./deployments/kubehound/docker-compose.dev.yaml"} - DefaultComposeDevPathUI = "./deployments/kubehound/docker-compose.ui.yaml" - DefaultComposeDevPathGRPC = "./deployments/kubehound/docker-compose.ingestor.yaml" + DefaultComposeDevPath = []string{"./deployments/kubehound/docker-compose.yaml", "./deployments/kubehound/docker-compose.dev.graph.yaml"} + DefaultComposeDevPathUI = "./deployments/kubehound/docker-compose.dev.ui.yaml" + DefaultComposeDevPathGRPC = "./deployments/kubehound/docker-compose.dev.ingestor.yaml" DefaultDatadogComposePath = "./deployments/kubehound/docker-compose.datadog.yaml" ) @@ -20,6 +21,7 @@ var ( uiTesting bool grpcTesting bool downTesting bool + profiles []string ) var ( @@ -28,9 +30,6 @@ var ( Hidden: true, Short: "[devOnly] Spawn the kubehound testing stack", Long: `[devOnly] Spawn the kubehound dev stack for the system-tests (build from dockerfile)`, - PersistentPreRunE: func(cobraCmd *cobra.Command, args []string) error { - return docker.NewBackend(cobraCmd.Context(), composePath) - }, RunE: func(cobraCmd *cobra.Command, args []string) error { if uiTesting { DefaultComposeDevPath = append(DefaultComposeDevPath, DefaultComposeDevPathUI) @@ -60,7 +59,11 @@ var ( ) func runEnv(ctx context.Context, composePaths []string) error { - err := docker.NewBackend(ctx, composePaths) + if uiTesting { + profiles = append(profiles, backend.DevUIProfile) + } + + err := docker.NewBackend(ctx, composePaths, profiles) if err != nil { return err } diff --git a/cmd/kubehound/root.go b/cmd/kubehound/root.go index bea8b6950..3bb20e810 100644 --- a/cmd/kubehound/root.go +++ b/cmd/kubehound/root.go @@ -27,7 +27,7 @@ var ( // auto spawning the backend stack if !skipBackend { // Forcing the embed docker config to be loaded - err := backend.NewBackend(cobraCmd.Context(), []string{""}) + err := backend.NewBackend(cobraCmd.Context(), []string{""}, backend.DefaultUIProfile) if err != nil { return err } diff --git a/deployments/kubehound/docker-compose.datadog.yaml b/deployments/kubehound/docker-compose.datadog.yaml index d6c49ad2e..53042241f 100644 --- a/deployments/kubehound/docker-compose.datadog.yaml +++ b/deployments/kubehound/docker-compose.datadog.yaml @@ -31,4 +31,4 @@ services: - kubenet networks: - kubenet: \ No newline at end of file + kubenet: diff --git a/deployments/kubehound/docker-compose.dev.graph.yaml b/deployments/kubehound/docker-compose.dev.graph.yaml new file mode 100644 index 000000000..184cefe30 --- /dev/null +++ b/deployments/kubehound/docker-compose.dev.graph.yaml @@ -0,0 +1,7 @@ +name: kubehound-dev +services: + kubegraph: + build: ./kubegraph/ + ports: + - "127.0.0.1:8182:8182" + - "127.0.0.1:8099:8099" diff --git a/deployments/kubehound/docker-compose.ingestor.yaml b/deployments/kubehound/docker-compose.dev.ingestor.yaml similarity index 87% rename from deployments/kubehound/docker-compose.ingestor.yaml rename to deployments/kubehound/docker-compose.dev.ingestor.yaml index 7c6c28c36..6319176e6 100644 --- a/deployments/kubehound/docker-compose.ingestor.yaml +++ b/deployments/kubehound/docker-compose.dev.ingestor.yaml @@ -1,3 +1,4 @@ +name: kubehound-dev services: grpc: build: @@ -10,4 +11,4 @@ services: - kubenet networks: - kubenet: \ No newline at end of file + kubenet: diff --git a/deployments/kubehound/docker-compose.dev.mongo.yaml b/deployments/kubehound/docker-compose.dev.mongo.yaml new file mode 100644 index 000000000..5e3fb37cc --- /dev/null +++ b/deployments/kubehound/docker-compose.dev.mongo.yaml @@ -0,0 +1,5 @@ +name: kubehound-dev +services: + mongodb: + ports: + - "127.0.0.1:27017:27017" diff --git a/deployments/kubehound/docker-compose.ui.yaml b/deployments/kubehound/docker-compose.dev.ui.yaml similarity index 54% rename from deployments/kubehound/docker-compose.ui.yaml rename to deployments/kubehound/docker-compose.dev.ui.yaml index 739665ed1..3daf69db2 100644 --- a/deployments/kubehound/docker-compose.ui.yaml +++ b/deployments/kubehound/docker-compose.dev.ui.yaml @@ -1,13 +1,7 @@ +name: kubehound-dev services: - notebook: + ui-jupyter: build: ./notebook/ restart: unless-stopped - ports: - - "127.0.0.1:8888:8888" - networks: - - kubenet volumes: - ./notebook/shared:/root/notebooks/shared - -networks: - kubenet: \ No newline at end of file diff --git a/deployments/kubehound/docker-compose.dev.yaml b/deployments/kubehound/docker-compose.dev.yaml deleted file mode 100644 index 09c31d0e5..000000000 --- a/deployments/kubehound/docker-compose.dev.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: kubehound-dev -services: - mongodb: - ports: - - "127.0.0.1:27017:27017" - volumes: - - mongodb_data:/data/db - networks: - - kind - - kubegraph: - build: ./kubegraph/ - ports: - - "127.0.0.1:8182:8182" - - "127.0.0.1:8099:8099" - volumes: - - kubegraph_data:/var/lib/janusgraph - networks: - - kind - -volumes: - mongodb_data: - kubegraph_data: - -networks: - kind: - external: true \ No newline at end of file diff --git a/deployments/kubehound/docker-compose.release.yaml b/deployments/kubehound/docker-compose.release.yaml new file mode 100644 index 000000000..bb9c4d660 --- /dev/null +++ b/deployments/kubehound/docker-compose.release.yaml @@ -0,0 +1,11 @@ +name: kubehound-release +services: + mongodb: + ports: + - "127.0.0.1:27017:27017" + + kubegraph: + image: ghcr.io/datadog/kubehound-ui:latest + ports: + - "127.0.0.1:8182:8182" + - "127.0.0.1:8099:8099" diff --git a/deployments/kubehound/docker-compose.release.yaml.tpl b/deployments/kubehound/docker-compose.release.yaml.tpl index 3d3462dca..3f4c20ffa 100644 --- a/deployments/kubehound/docker-compose.release.yaml.tpl +++ b/deployments/kubehound/docker-compose.release.yaml.tpl @@ -3,33 +3,12 @@ services: mongodb: ports: - "127.0.0.1:27017:27017" - volumes: - - mongodb_data:/data/db kubegraph: image: ghcr.io/datadog/kubehound-graph:{{ .VersionTag }} ports: - "127.0.0.1:8182:8182" - "127.0.0.1:8099:8099" - volumes: - - kubegraph_data:/var/lib/janusgraph - ui: + ui-jupyter: image: ghcr.io/datadog/kubehound-ui:{{ .VersionTag }} - restart: unless-stopped - ports: - - "127.0.0.1:8888:8888" - networks: - - kubenet - labels: - com.datadoghq.ad.logs: '[{"app": "kubeui", "service": "kubehound"}]' - volumes: - - kubeui_data:/root/notebooks/shared - -volumes: - mongodb_data: - kubegraph_data: - kubeui_data: - -networks: - kubenet: \ No newline at end of file diff --git a/deployments/kubehound/docker-compose.testing.yaml b/deployments/kubehound/docker-compose.testing.yaml index 25da5ff98..294891c80 100644 --- a/deployments/kubehound/docker-compose.testing.yaml +++ b/deployments/kubehound/docker-compose.testing.yaml @@ -3,17 +3,9 @@ services: mongodb: ports: - "127.0.0.1:27018:27017" - networks: - - kind kubegraph: build: ./kubegraph/ - networks: - - kind ports: - "127.0.0.1:8183:8182" - "127.0.0.1:8090:8099" - -networks: - kind: - external: true \ No newline at end of file diff --git a/deployments/kubehound/docker-compose.yaml b/deployments/kubehound/docker-compose.yaml index 07c6ae562..8e2025619 100644 --- a/deployments/kubehound/docker-compose.yaml +++ b/deployments/kubehound/docker-compose.yaml @@ -14,6 +14,8 @@ services: interval: 10s timeout: 2s retries: 10 + volumes: + - mongodb_data:/data/db kubegraph: restart: unless-stopped @@ -26,6 +28,54 @@ services: retries: 3 labels: com.datadoghq.ad.logs: '[{"app": "kubegraph", "service": "kubehound"}]' + volumes: + - kubegraph_data:/var/lib/janusgraph + + ui-jupyter: + restart: unless-stopped + profiles: + - jupyter + ports: + - "127.0.0.1:8888:8888" + networks: + - kubenet + labels: + com.datadoghq.ad.logs: '[{"app": "kubeui", "service": "kubehound"}]' + volumes: + - kubeui_data:/root/notebooks/shared + environment: + - NOTEBOOK_PASSWORD=admin + + ui-invana-engine: + image: invanalabs/invana-engine:latest + profiles: + - invana + restart: unless-stopped + networks: + - kubenet + ports: + - 127.0.0.1:8200:8200 + environment: + GREMLIN_SERVER_URL: ws://kubegraph:8182/gremlin + depends_on: + - kubegraph + + ui-invana-studio: + image: invanalabs/invana-studio:latest + restart: unless-stopped + profiles: + - invana + networks: + - kubenet + ports: + - 127.0.0.1:8300:8300 + depends_on: + - ui-invana-engine networks: - kubenet: \ No newline at end of file + kubenet: + +volumes: + mongodb_data: + kubegraph_data: + kubeui_data: diff --git a/deployments/kubehound/notebook/Dockerfile b/deployments/kubehound/notebook/Dockerfile index 27f79eae5..3baa17ae3 100644 --- a/deployments/kubehound/notebook/Dockerfile +++ b/deployments/kubehound/notebook/Dockerfile @@ -18,7 +18,6 @@ ENV GRAPH_NOTEBOOK_PORT="8182" ENV NOTEBOOK_PORT="8888" ENV LAB_PORT="8889" ENV GRAPH_NOTEBOOK_SSL="True" -ENV NOTEBOOK_PASSWORD="admin" # "when the SIGTERM signal is sent to the docker process, it immediately quits and all established connections are closed" # "graceful stop is triggered when the SIGUSR1 signal is sent to the docker process" diff --git a/pkg/backend/containers.go b/pkg/backend/containers.go index ba4d8cb58..9d8726437 100644 --- a/pkg/backend/containers.go +++ b/pkg/backend/containers.go @@ -24,15 +24,15 @@ type Backend struct { dockerCli *command.DockerCli } -func NewBackend(ctx context.Context, composeFilePaths []string) error { +func NewBackend(ctx context.Context, composeFilePaths []string, profiles []string) error { var err error - currentBackend, err = newBackend(ctx, composeFilePaths) + currentBackend, err = newBackend(ctx, composeFilePaths, profiles) return err } -func newBackend(ctx context.Context, composeFilePaths []string) (*Backend, error) { - project, err := loadProject(ctx, composeFilePaths) +func newBackend(ctx context.Context, composeFilePaths []string, profiles []string) (*Backend, error) { + project, err := loadProject(ctx, composeFilePaths, profiles) if err != nil { return nil, err } diff --git a/pkg/backend/project.go b/pkg/backend/project.go index 791aa2ef5..0f9b041af 100644 --- a/pkg/backend/project.go +++ b/pkg/backend/project.go @@ -21,19 +21,22 @@ import ( var ( DefaultReleaseComposePaths = []string{"docker-compose.yaml", "docker-compose.release.yaml.tpl"} DefaultDatadogComposePath = "docker-compose.datadog.yaml" + DefaultUIProfile = []string{DevUIProfile} + + DevUIProfile = "jupyter" ) -func loadProject(ctx context.Context, composeFilePaths []string) (*types.Project, error) { +func loadProject(ctx context.Context, composeFilePaths []string, profiles []string) (*types.Project, error) { var project *types.Project var err error switch { case len(composeFilePaths) != 0 && len(composeFilePaths[0]) != 0: log.I.Infof("Loading backend from file %s", composeFilePaths) - project, err = loadComposeConfig(ctx, composeFilePaths) + project, err = loadComposeConfig(ctx, composeFilePaths, profiles) default: log.I.Infof("Loading backend from default embedded") - project, err = loadEmbeddedConfig(ctx) + project, err = loadEmbeddedConfig(ctx, profiles) } if err != nil { @@ -66,11 +69,12 @@ func loadProject(ctx context.Context, composeFilePaths []string) (*types.Project return project, nil } -func loadComposeConfig(ctx context.Context, composeFilePaths []string) (*types.Project, error) { +func loadComposeConfig(ctx context.Context, composeFilePaths []string, profiles []string) (*types.Project, error) { options, err := cli.NewProjectOptions( composeFilePaths, cli.WithOsEnv, cli.WithDotEnv, + cli.WithProfiles(profiles), ) if err != nil { return nil, err @@ -79,7 +83,7 @@ func loadComposeConfig(ctx context.Context, composeFilePaths []string) (*types.P return cli.ProjectFromOptions(ctx, options) } -func loadEmbeddedConfig(ctx context.Context) (*types.Project, error) { +func loadEmbeddedConfig(ctx context.Context, profiles []string) (*types.Project, error) { var dockerComposeFileData map[interface{}]interface{} var err error var hostname string @@ -122,22 +126,29 @@ func loadEmbeddedConfig(ctx context.Context) (*types.Project, error) { }, } - return loader.LoadWithContext(ctx, opts) + return loader.LoadWithContext(ctx, opts, loader.WithProfiles(profiles)) } func loadEmbeddedDockerCompose(_ context.Context, filepath string, dockerComposeFileData map[interface{}]interface{}) (map[interface{}]interface{}, error) { var localYaml map[interface{}]interface{} - var localData []byte - var err error - // Setting the version tag for the release dynamically - // For local version (when the version is "dirty", using latest to have a working binary) - version := map[string]string{"VersionTag": "latest"} - if !strings.HasSuffix(config.BuildVersion, "dirty") { - version["VersionTag"] = config.BuildVersion + localData, err := embedconfigdocker.F.ReadFile(filepath) + if err != nil { + return nil, fmt.Errorf("reading embed config: %w", err) } + // Dynamically setting the version tag for the release using a template file if strings.HasSuffix(filepath, ".tpl") { + // Setting the version tag for the release dynamically + version := map[string]string{"VersionTag": config.BuildVersion} + + // For local version (when the version is "dirty", using latest to have a working binary) + // For any branch outside of main, using latest image as the current tag will cover (including the commit sha in the tag) + if strings.HasSuffix(config.BuildBranch, "dirty") || config.BuildBranch != "main" { + log.I.Warnf("Loading the kubehound images with tag latest - dev branch detected") + version["VersionTag"] = "latest" + } + tmpl, err := template.New(filepath).ParseFS(embedconfigdocker.F, filepath) if err != nil { return nil, fmt.Errorf("new template: %w", err) @@ -149,11 +160,6 @@ func loadEmbeddedDockerCompose(_ context.Context, filepath string, dockerCompose return nil, fmt.Errorf("executing template: %w", err) } localData = buf.Bytes() - } else { - localData, err = embedconfigdocker.F.ReadFile(filepath) - if err != nil { - return nil, fmt.Errorf("reading embed config: %w", err) - } } err = yaml.Unmarshal(localData, &localYaml) diff --git a/pkg/config/config.go b/pkg/config/config.go index 6ba59986b..fb5da4970 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -14,6 +14,7 @@ import ( var ( BuildVersion string // This should be overwritten by the go build -X flags + BuildBranch string // This should be overwritten by the go build -X flags BuildArch string // This should be overwritten by the go build -X flags BuildOs string // This should be overwritten by the go build -X flags )