Skip to content

feat(alert-forwarder): replace Python with Go implementation#18

Open
calghar wants to merge 2 commits intodynatrace-oss:mainfrom
calghar:feat/alert-forwarder-go-implementation
Open

feat(alert-forwarder): replace Python with Go implementation#18
calghar wants to merge 2 commits intodynatrace-oss:mainfrom
calghar:feat/alert-forwarder-go-implementation

Conversation

@calghar
Copy link
Member

@calghar calghar commented Jul 11, 2025

Description

This PR replaces the Python alert-forwarder with a high-performance Go implementation.

Type of Change

  • Bug fix
  • [] New feature
  • Performance improvement
  • [] Breaking change
  • Documentation update

Motivation

The Python alert-forwarder works well but has some limitations:

  • High memory footprint for a simple service
  • Large container image increases deployment time
  • Runtime interpretation overhead
  • Prevents all components of Koney being in Go

The Go implementation addresses all these issues while maintaining 100% compatibility.

Changes

  • Replaced alert-forwarder/*.py with Go implementation
  • Added proper Go module structure with go.mod
  • Updated Dockerfile for multi-arch builds
  • Maintained identical API endpoints and behavior
  • Preserved all existing functionality

Testing

Tested on:

  • Kind cluster (Kubernetes 1.29)
  • M1 Mac (arm64)
  • Linux amd64 (CI)

Compatibility

  • ✅ No breaking changes
  • ✅ Same configuration (PORT env var)
  • ✅ Same API endpoints
  • ✅ Same JSON output format
  • ✅ Same Kubernetes RBAC requirements

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Code builds without warnings
  • Tests pass locally
  • Documentation updated

Additional Notes

The Go implementation uses the official Kubernetes client-go library, providing better compatibility with future Kubernetes versions. The code structure follows Go best practices with clear separation of concerns.

Happy to make any adjustments based on review feedback.

@calghar calghar requested a review from blu3r4y as a code owner July 11, 2025 23:55
@dynatrace-cla-bot
Copy link

dynatrace-cla-bot commented Jul 11, 2025

CLA assistant check
All committers have signed the CLA.

Copy link
Member

@blu3r4y blu3r4y left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @f4r00q for the PR, looks like a great rewrite of the Python source. I worked through the code and made plenty of suggestions. Let me know if you find the time to integrate them, otherwise, I might also be able to take care of some of them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ISSUE] Please don't delete README.md

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how this got deleted

@@ -1,19 +1,32 @@
FROM python:3.13-slim@sha256:21e39cf1815802d4c6f89a0d3a166cc67ce58f95b6d1639e68a394c99310d2e5
# Copyright (c) 2025 Dynatrace LLC
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ISSUE] License header should only be added to source code files. Please remove it from the Dockerfile.

# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Q] What is --platform=$BUILDPLATFORM doing? If this is useful, should we also add it to the main Dockerfile?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its to enable easy cross-platform build. It would make sense to add it to the main file as well

# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ISSUE] Please use Go 1.24 as this is the most recent version

# can be seen more easily (they are logged regardless)
ENV UVICORN_LOG_LEVEL=error

FROM alpine:latest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Q] Could you use gcr.io/distroless/static:nonroot here?

functionName, _ := processKprobe["function_name"].(string)
fileAccessFns := []string{"security_file_permission", "security_mmap_file"}

for _, fn := range fileAccessFns {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NIT] Those two lines (the for and the if) could be simplified to the following:

if slices.Contains(fileAccessFns, functionName) {
  trapType = TrapTypeFilesystemHoneytoken
  // ...
}

for _, fn := range fileAccessFns {
if functionName == fn {
trapType = TrapTypeFilesystemHoneytoken
if args, ok := processKprobe["args"].([]interface{}); ok && len(args) > 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NIT] That piece of code looks very hard to read - actually, also, in the Python version. However, in my recent PR I tried to extract this field resolution for honeytokens into their own method. Could you try to do the same for the Golang version here? For reference: https://github.com/dynatrace-oss/koney/blob/feat/TR-4934-dynatrace-ingest/alert-forwarder/forwarder/tetragon.py#L121

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


timestamp, _ := event["time"].(string)
if timestamp == "" {
timestamp = time.Now().Format(time.RFC3339)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ISSUE] No, please not default to the current time, let the field be empty if we cannot resolve it.

func resolveDeceptionPolicyName(kubeClient *kubernetes.Clientset, tracingPolicyName string) (string, error) {
ctx := context.Background()

// Create a dynamic client for the custom resource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ISSUE] Hmm, well, if we add github.com/cilium/tetragon as a dependency in go.mod we could use the typed client. If this code is integrated with the main controller, we would already have it.

Anyways, maybe we want to still stick with the untyped client here. But then, I think we shouldn't initialize the client here in tetragon.go but rather in main.go, and then pass the dynamic client. Reason being that client initialization should be decoupled from using them, I dislike that tetragon.go is reading the cluster config again and creating a new client here.

}

// Helper functions
func getStringValue(m map[string]interface{}, key string) string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[PRAISE] Useful stuff!

@calghar
Copy link
Member Author

calghar commented Jul 21, 2025

Thanks @f4r00q for the PR, looks like a great rewrite of the Python source. I worked through the code and made plenty of suggestions. Let me know if you find the time to integrate them, otherwise, I might also be able to take care of some of them.

I can take care of this. Give me a few days to get to it. 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants