diff --git a/go.mod b/go.mod index 0965eabed..f5231c8d6 100644 --- a/go.mod +++ b/go.mod @@ -174,3 +174,4 @@ require ( ) replace github.com/vmware/go-ipfix => github.com/jotak/go-ipfix v0.0.0-20250708115123-407c539ea101 +replace github.com/netobserv/netobserv-ebpf-agent => github.com/jotak/netobserv-agent v0.0.0-20251201132656-d1dee7de8bca diff --git a/go.sum b/go.sum index 8c0fb2cd5..2afbe0379 100644 --- a/go.sum +++ b/go.sum @@ -177,6 +177,8 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jotak/go-ipfix v0.0.0-20250708115123-407c539ea101 h1:tpaHjydMAy2MTukKIUAVK4xIFUpL12xuexA0FuTVpuo= github.com/jotak/go-ipfix v0.0.0-20250708115123-407c539ea101/go.mod h1:GgFbcmEGqMQfA7jDC9UVLKAelNh2sy1jsxyV7Tor3Ig= +github.com/jotak/netobserv-agent v0.0.0-20251201132656-d1dee7de8bca h1:VQMzly3wKRXwWm0V8Bnzj2Us786hKAR1CCfH/24+yd8= +github.com/jotak/netobserv-agent v0.0.0-20251201132656-d1dee7de8bca/go.mod h1:ZQf6WKnhdfdaR5PQ/Fc99l4/doL94OQeTkQknwFiQZo= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -257,8 +259,6 @@ github.com/netobserv/gopipes v0.3.0 h1:IYmPnnAVCdSK7VmHmpFhrVBOEm45qpgbZmJz1sSW+ github.com/netobserv/gopipes v0.3.0/go.mod h1:N7/Gz05EOF0CQQSKWsv3eof22Cj2PB08Pbttw98YFYU= github.com/netobserv/loki-client-go v0.0.0-20251014110557-40bc8d2e6cf3 h1:rxQipq0xpoiao7ifls/82JCcOVALC4n08ppTLCUFGL4= github.com/netobserv/loki-client-go v0.0.0-20251014110557-40bc8d2e6cf3/go.mod h1:Zb/jtD3Lnu88Poo+jnhTASzxYnvncmHOoZaT93xQjJ8= -github.com/netobserv/netobserv-ebpf-agent v1.10.0-community.0.20251125162210-4be10c36721e h1:hGJIbcfTbzjpuZ9K7hVwD/6+KijR0TfqJjmXeigQELc= -github.com/netobserv/netobserv-ebpf-agent v1.10.0-community.0.20251125162210-4be10c36721e/go.mod h1:ZQf6WKnhdfdaR5PQ/Fc99l4/doL94OQeTkQknwFiQZo= github.com/netsampler/goflow2 v1.3.7 h1:XZaTy8kkMnGXpJ9hS3KbO1McyrFTpVNhVFEx9rNhMmc= github.com/netsampler/goflow2 v1.3.7/go.mod h1:4UZsVGVAs//iMCptUHn3WNScztJeUhZH7kDW2+/vDdQ= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= diff --git a/pkg/api/ingest_grpc.go b/pkg/api/ingest_grpc.go index 5da4128cc..fdad54651 100644 --- a/pkg/api/ingest_grpc.go +++ b/pkg/api/ingest_grpc.go @@ -1,6 +1,9 @@ package api type IngestGRPCProto struct { - Port int `yaml:"port,omitempty" json:"port,omitempty" doc:"the port number to listen on"` - BufferLen int `yaml:"bufferLength,omitempty" json:"bufferLength,omitempty" doc:"the length of the ingest channel buffer, in groups of flows, containing each group hundreds of flows (default: 100)"` + Port int `yaml:"port,omitempty" json:"port,omitempty" doc:"the port number to listen on"` + BufferLen int `yaml:"bufferLength,omitempty" json:"bufferLength,omitempty" doc:"the length of the ingest channel buffer, in groups of flows, containing each group hundreds of flows (default: 100)"` + CertPath string `yaml:"certPath,omitempty" json:"certPath,omitempty" doc:"path of the TLS certificate, if any"` + KeyPath string `yaml:"keyPath,omitempty" json:"keyPath,omitempty" doc:"path of the TLS certificate key, if any"` + ClientCAPath string `yaml:"clientCAPath,omitempty" json:"clientCAPath,omitempty" doc:"path of the client TLS CA, if any, for mutual TLS"` } diff --git a/pkg/pipeline/encode/encode_kafka_test.go b/pkg/pipeline/encode/encode_kafka_test.go index 00e02d93e..f293f3557 100644 --- a/pkg/pipeline/encode/encode_kafka_test.go +++ b/pkg/pipeline/encode/encode_kafka_test.go @@ -122,7 +122,7 @@ func Test_TLSConfigCA(t *testing.T) { func Test_MutualTLSConfig(t *testing.T) { test.ResetPromRegistry() - ca, user, userKey, cleanup := test.CreateAllCerts(t) + ca, user, userKey, _, _, cleanup := test.CreateAllCerts(t) defer cleanup() pipeline := config.NewIPFIXPipeline("ingest", api.IngestIpfix{}) pipeline.EncodeKafka("encode-kafka", api.EncodeKafka{ diff --git a/pkg/pipeline/ingest/ingest_grpc.go b/pkg/pipeline/ingest/ingest_grpc.go index 5a3e80e75..5a14259a6 100644 --- a/pkg/pipeline/ingest/ingest_grpc.go +++ b/pkg/pipeline/ingest/ingest_grpc.go @@ -2,7 +2,11 @@ package ingest import ( "context" + "crypto/tls" + "crypto/x509" + "errors" "fmt" + "os" "github.com/netobserv/flowlogs-pipeline/pkg/api" "github.com/netobserv/flowlogs-pipeline/pkg/config" @@ -15,6 +19,7 @@ import ( "github.com/sirupsen/logrus" grpc2 "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" ) @@ -33,14 +38,14 @@ type GRPCProtobuf struct { } func NewGRPCProtobuf(opMetrics *operational.Metrics, params config.StageParam) (*GRPCProtobuf, error) { - netObserv := api.IngestGRPCProto{} + cfg := api.IngestGRPCProto{} if params.Ingest != nil && params.Ingest.GRPC != nil { - netObserv = *params.Ingest.GRPC + cfg = *params.Ingest.GRPC } - if netObserv.Port == 0 { - return nil, fmt.Errorf("ingest port not specified") + if cfg.Port == 0 { + return nil, errors.New("ingest port not specified") } - bufLen := netObserv.BufferLen + bufLen := cfg.BufferLen if bufLen == 0 { bufLen = defaultBufferLen } @@ -54,8 +59,40 @@ func NewGRPCProtobuf(opMetrics *operational.Metrics, params config.StageParam) ( withBatchSizeBytes(), withStageDuration(), ) - collector, err := grpc.StartCollector(netObserv.Port, flowPackets, - grpc.WithGRPCServerOptions(grpc2.UnaryInterceptor(instrumentGRPC(metrics)))) + var opts []grpc2.ServerOption + // GRPC metrics + opts = append(opts, grpc2.UnaryInterceptor(instrumentGRPC(metrics))) + + if cfg.CertPath != "" && cfg.KeyPath != "" { + // TLS + cert, err := tls.LoadX509KeyPair(cfg.CertPath, cfg.KeyPath) + if err != nil { + return nil, fmt.Errorf("cannot load configured certificate: %w", err) + } + tlsCfg := &tls.Config{ + Certificates: []tls.Certificate{cert}, + ClientAuth: tls.NoClientCert, + } + if cfg.ClientCAPath != "" { + // mTLS + caCert, err := os.ReadFile(cfg.ClientCAPath) + if err != nil { + return nil, fmt.Errorf("cannot load configured client CA certificate: %w", err) + } + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(caCert) + tlsCfg.ClientAuth = tls.RequireAndVerifyClientCert + tlsCfg.ClientCAs = pool + glog.Info("Starting GRPC server with mTLS") + } else { + glog.Info("Starting GRPC server with TLS") + } + opts = append(opts, grpc2.Creds(credentials.NewTLS(tlsCfg))) + } else { + glog.Info("Starting GRPC server - no TLS") + } + + collector, err := grpc.StartCollector(cfg.Port, flowPackets, grpc.WithGRPCServerOptions(opts...)) if err != nil { return nil, err } diff --git a/pkg/pipeline/ingest/ingest_grpc_test.go b/pkg/pipeline/ingest/ingest_grpc_test.go new file mode 100644 index 000000000..2758845a1 --- /dev/null +++ b/pkg/pipeline/ingest/ingest_grpc_test.go @@ -0,0 +1,149 @@ +package ingest + +import ( + "context" + "testing" + "time" + + test2 "github.com/mariomac/guara/pkg/test" + "github.com/netobserv/flowlogs-pipeline/pkg/api" + "github.com/netobserv/flowlogs-pipeline/pkg/config" + "github.com/netobserv/flowlogs-pipeline/pkg/operational" + "github.com/netobserv/flowlogs-pipeline/pkg/test" + flowgrpc "github.com/netobserv/netobserv-ebpf-agent/pkg/grpc/flow" + "github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type tlsConfig struct { + clientCertPath string + clientKeyPath string + serverCAPathForClient string + serverCertPath string + serverKeyPath string + clientCAPathForServer string +} + +func TestGRPC_NoTLS(t *testing.T) { + runGRPCTestForTLS(t, tlsConfig{}, "") +} + +func TestGRPC_SimpleTLS(t *testing.T) { + ca, _, _, cert, key, cleanup := test.CreateAllCerts(t) + defer cleanup() + runGRPCTestForTLS( + t, + tlsConfig{ + serverCAPathForClient: ca, + serverCertPath: cert, + serverKeyPath: key, + }, + "", + ) +} + +func TestGRPC_MutualTLS(t *testing.T) { + ca, user, userKey, serverCert, serverKey, cleanup := test.CreateAllCerts(t) + defer cleanup() + runGRPCTestForTLS( + t, + tlsConfig{ + clientCAPathForServer: ca, + clientCertPath: user, + clientKeyPath: userKey, + serverCAPathForClient: ca, + serverCertPath: serverCert, + serverKeyPath: serverKey, + }, + "", + ) +} + +func TestGRPC_FailExpectingTLS(t *testing.T) { + _, _, _, cert, key, cleanup := test.CreateAllCerts(t) + defer cleanup() + runGRPCTestForTLS( + t, + tlsConfig{ + serverCAPathForClient: "", // by not providing server CA, the client is in NOTLS mode + serverCertPath: cert, + serverKeyPath: key, + }, + "connection error", + ) +} + +func TestGRPC_FailExpectingMTLS(t *testing.T) { + ca, _, _, serverCert, serverKey, cleanup := test.CreateAllCerts(t) + defer cleanup() + runGRPCTestForTLS( + t, + tlsConfig{ + clientCAPathForServer: ca, + clientCertPath: "", // by not providing client cert, the client is in simple TLS mode + clientKeyPath: "", + serverCAPathForClient: ca, + serverCertPath: serverCert, + serverKeyPath: serverKey, + }, + "write tcp", // would prefer a more explicit error, but that's all that we get: "write tcp 127.0.0.1:54154->127.0.0.1:40763: write: broken pipe" + ) +} + +// nolint:gocritic // hugeParam; don't care in tests +func runGRPCTestForTLS(t *testing.T, certs tlsConfig, expectErrorContains string) { + port, err := test2.FreeTCPPort() + require.NoError(t, err) + + out := make(chan config.GenericMap) + cfg := &config.Ingest{ + GRPC: &api.IngestGRPCProto{ + Port: port, + CertPath: certs.serverCertPath, + KeyPath: certs.serverKeyPath, + ClientCAPath: certs.clientCAPathForServer, + }, + } + ingester, err := NewGRPCProtobuf(operational.NewMetrics(&config.MetricsSettings{}), config.StageParam{Ingest: cfg}) + require.NoError(t, err) + + go ingester.Ingest(out) + + flowSender, err := flowgrpc.ConnectClient("127.0.0.1", port, certs.serverCAPathForClient, certs.clientCertPath, certs.clientKeyPath) + require.NoError(t, err) + defer flowSender.Close() + + record := &pbflow.Records{ + Entries: []*pbflow.Record{{ + EthProtocol: 2048, + Transport: &pbflow.Transport{}, + Network: &pbflow.Network{ + SrcAddr: &pbflow.IP{ + IpFamily: &pbflow.IP_Ipv4{Ipv4: 0x01020304}, + }, + DstAddr: &pbflow.IP{ + IpFamily: &pbflow.IP_Ipv4{Ipv4: 0x05060708}, + }, + }, + }}, + } + + _, err = flowSender.Client().Send(context.Background(), record) + if expectErrorContains != "" { + require.ErrorContains(t, err, expectErrorContains) + return + } + require.NoError(t, err) + + var received config.GenericMap + select { + case r := <-out: + received = r + case <-time.After(timeout): + require.Fail(t, "timeout while waiting for Ingester to receive and process data") + } + + assert.Equal(t, "1.2.3.4", received["SrcAddr"]) + assert.Equal(t, "5.6.7.8", received["DstAddr"]) +} diff --git a/pkg/pipeline/ingest/ingest_kafka_test.go b/pkg/pipeline/ingest/ingest_kafka_test.go index bf08498e7..119ac11aa 100644 --- a/pkg/pipeline/ingest/ingest_kafka_test.go +++ b/pkg/pipeline/ingest/ingest_kafka_test.go @@ -242,7 +242,7 @@ func Test_TLSConfigCA(t *testing.T) { func Test_MutualTLSConfig(t *testing.T) { test.ResetPromRegistry() - ca, user, userKey, cleanup := test.CreateAllCerts(t) + ca, user, userKey, _, _, cleanup := test.CreateAllCerts(t) defer cleanup() stage := config.NewKafkaPipeline("ingest-kafka", api.IngestKafka{ Brokers: []string{"any"}, diff --git a/pkg/pipeline/pipeline_test.go b/pkg/pipeline/pipeline_test.go index 27ab41ea5..aa2238fd5 100644 --- a/pkg/pipeline/pipeline_test.go +++ b/pkg/pipeline/pipeline_test.go @@ -168,7 +168,7 @@ parameters: // yield thread to allow pipe services correctly start time.Sleep(10 * time.Millisecond) - flowSender, err := grpc.ConnectClient("127.0.0.1", port) + flowSender, err := grpc.ConnectClient("127.0.0.1", port, "", "", "") require.NoError(t, err) defer flowSender.Close() diff --git a/pkg/pipeline/write/grpc/client.go b/pkg/pipeline/write/grpc/client.go index 9af18a435..d985d411c 100644 --- a/pkg/pipeline/write/grpc/client.go +++ b/pkg/pipeline/write/grpc/client.go @@ -1,29 +1,38 @@ package grpc import ( - "flag" - "log" + "crypto/tls" pb "github.com/netobserv/flowlogs-pipeline/pkg/pipeline/write/grpc/genericmap" "github.com/netobserv/netobserv-ebpf-agent/pkg/utils" + "github.com/sirupsen/logrus" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" ) +var glog = logrus.WithField("component", "write.GRPCClient") + // ClientConnection wraps a gRPC+protobuf connection type ClientConnection struct { client pb.CollectorClient conn *grpc.ClientConn } -func ConnectClient(hostIP string, hostPort int) (*ClientConnection, error) { - flag.Parse() +func ConnectClient(hostIP string, hostPort int, tlsConfig *tls.Config) (*ClientConnection, error) { // Set up a connection to the server. + var creds credentials.TransportCredentials + if tlsConfig != nil { + creds = credentials.NewTLS(tlsConfig) + } else { + glog.Info("Using GRPC - No TLS") + creds = insecure.NewCredentials() + } socket := utils.GetSocket(hostIP, hostPort) - conn, err := grpc.NewClient(socket, grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.NewClient(socket, grpc.WithTransportCredentials(creds)) if err != nil { - log.Fatalf("did not connect: %v", err) + return nil, err } return &ClientConnection{ diff --git a/pkg/pipeline/write/grpc/grpc_test.go b/pkg/pipeline/write/grpc/grpc_test.go index ea6442377..f5b8fe63c 100644 --- a/pkg/pipeline/write/grpc/grpc_test.go +++ b/pkg/pipeline/write/grpc/grpc_test.go @@ -23,7 +23,7 @@ func TestGRPCCommunication(t *testing.T) { serverOut := make(chan *genericmap.Flow) _, err = StartCollector(port, serverOut) require.NoError(t, err) - cc, err := ConnectClient("127.0.0.1", port) + cc, err := ConnectClient("127.0.0.1", port, nil) require.NoError(t, err) client := cc.Client() @@ -76,7 +76,7 @@ func TestConstructorOptions(t *testing.T) { return handler(ctx, req) }))) require.NoError(t, err) - cc, err := ConnectClient("127.0.0.1", port) + cc, err := ConnectClient("127.0.0.1", port, nil) require.NoError(t, err) client := cc.Client() diff --git a/pkg/pipeline/write/write_grpc.go b/pkg/pipeline/write/write_grpc.go index c89d5f361..ec3c514b5 100644 --- a/pkg/pipeline/write/write_grpc.go +++ b/pkg/pipeline/write/write_grpc.go @@ -46,7 +46,7 @@ func NewWriteGRPC(params config.StageParam) (Writer, error) { return nil, fmt.Errorf("write.grpc param is mandatory: %v", params.Write) } logrus.Debugf("NewWriteGRPC ConnectClient %s:%d...", writeGRPC.hostIP, writeGRPC.hostPort) - clientConn, err := grpc.ConnectClient(writeGRPC.hostIP, writeGRPC.hostPort) + clientConn, err := grpc.ConnectClient(writeGRPC.hostIP, writeGRPC.hostPort, nil) if err != nil { return nil, err } diff --git a/pkg/pipeline/write/write_grpc_test.go b/pkg/pipeline/write/write_grpc_test.go index fddd07f77..a3ef4711f 100644 --- a/pkg/pipeline/write/write_grpc_test.go +++ b/pkg/pipeline/write/write_grpc_test.go @@ -13,7 +13,7 @@ import ( func Test_WriteGRPC(t *testing.T) { port, err := test.FreeTCPPort() require.NoError(t, err) - cc, err := grpc.ConnectClient("127.0.0.1", port) + cc, err := grpc.ConnectClient("127.0.0.1", port, nil) require.NoError(t, err) ws := writeGRPC{ hostIP: "127.0.0.1", diff --git a/pkg/test/tls.go b/pkg/test/tls.go index c08a4887f..68e60fea1 100644 --- a/pkg/test/tls.go +++ b/pkg/test/tls.go @@ -6,74 +6,137 @@ import ( "github.com/stretchr/testify/require" ) -// Fake certificates / private key for test +// Fake certificates / private keys for test -const userCert string = `-----BEGIN CERTIFICATE----- -MIICuzCCAaMCCQCwxTs8nSaQAzANBgkqhkiG9w0BAQsFADAtMRMwEQYDVQQKDApp -by5zdHJpbXppMRYwFAYDVQQDDA1jbGllbnRzLWNhIHYwMB4XDTE5MDgyNjExMjgx -MVoXDTIwMDgyNTExMjgxMVowEjEQMA4GA1UEAwwHZm9vdXNlcjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMjkeJpZkNanRb3MjXwi7EQV0Sj2HbssT9Pr -p0L1Ha4aqEO3mgjBR5a2/iM+z5b1bF33S1GJiKkuz9Dq/BiFOmqBJSHqZQBGtFus -vbBFeV+pkS4OwAX68QRhzfD/rN/zhHcH9Ms1WGiV11KRMi15TPdgn1wP31qdq67u -VgQr2HlExQfzW5tEc5UpN6srRswnVxelPvXFpDsk5GORKvMhHshU8DJXx/vdHk5J -GT8KW+wi1nfmVTV79ZQR6ndmPR4PaoeOf/wawKews9N4jr17uQNvqQn488s+KNrT -O7eGd37x3tpPfAjqZmMKpt4sD/Z5MJs8ryakEQzAn3TKZnwo5CECAwEAATANBgkq -hkiG9w0BAQsFAAOCAQEAWNNALALbhsEaOpBz8J19FFKNh5JtUiBecQWNBnA3HXt5 -X61dubaEwQMQqPZcIsdInkQ5n90OBb0dAY7A9wDlihmHc0GtcSo5NTMGELLTWH+g -GQO62OyUOUmkAgxhJZ/MDPzJSko9mUtiwXuovOt7EqyTvmvNjGBDwulcYMZ/VpQm -wxUFbfw4+mgVBH9lsWvAqNdflyXyEV1KxsHaApDeoG66sN2NSr09mGtADTrYskpM -qG9UQeYdb96qGmnkPWKlDKCl0s5ch9t3BZKhgNztmUtNUQiT7bH1whwIbyNA7/yo -XcB7AfxW+DNCSL51qnsOJoTG7N9gbfNhHpwlqHVuKA== +// CA generated with: +// openssl req -newkey rsa:2048 -nodes -days 3650 -x509 -keyout ca.key -out ca.crt -subj "/CN=*" +const caCert string = `-----BEGIN CERTIFICATE----- +MIIC+TCCAeGgAwIBAgIULGvHF3aRgJryhvb/9lQMR8TPpIYwDQYJKoZIhvcNAQEL +BQAwDDEKMAgGA1UEAwwBKjAeFw0yMzA4MDIwODUzMTdaFw0zMzA3MzAwODUzMTda +MAwxCjAIBgNVBAMMASowggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK +NcqKT0leAUzpkmp0x7PYGXvGSXviN7zbo415he1mIYWvuGBhB2J3aUlafABJ2wxD +tdjXFDUI2T9BjRDrbsha4LzhzeBFc3xorlp/KDVZnhgbbHeCL8bfgQrfjsFzAXNa +QEdoTwBRs8fznXVzQ7ecWhobyT9M84v2Mlh93YQFEueiHx0Z8jFUESn6vcOXWXqF +8VZWlPPsRauy79zFkCmr09UKxyOWGtImM+9Sgvda7oZGkJBZ1gvhBULOG72ekhsH +RtlT4Xmf4irINm4vRnZcFRJgwaOsCvX/9gyDCfoJ0ioUZ5ZmhYNGJeNSi63LnAZm +1Zsa4ZOGvtdsdAgaZN1jAgMBAAGjUzBRMB0GA1UdDgQWBBQ34SoDX/LC+i2h57cI +aOGmGZTgBzAfBgNVHSMEGDAWgBQ34SoDX/LC+i2h57cIaOGmGZTgBzAPBgNVHRMB +Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBfFSuPYJK0Gt8psgARSHLJUzSB +X9XmcIYpeFIZk5GqmGnj/0op4w3R/T/TwYTf7+FvqGIKaMyXSgeJJu1uC1M/AI11 +nQmv9XtLmX2BJtKWORoBOPYKnoGSaljoQJZzJJ09lzasHLy68cYezbqb+3+EIGEa +vBKdFgbDyYQpSIs3oAIW9drcEywFf8s5ZSewPhaz1byDlvTHJjKNGoWwm/tlXhv/ +GXHWiYftbJRGHDiA9BqZT2g/vMz/1e9k5wSek+fqaBQNS7nEijUz+Qk0LlmagZV3 +kom8Fkz5HTYkmZVzXPW8spFEuIibCgRK1qA1RuDsyNxMnk3c1jcR8B5AJ/VI -----END CERTIFICATE-----` -const userKey string = `-----BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDI5HiaWZDWp0W9 -zI18IuxEFdEo9h27LE/T66dC9R2uGqhDt5oIwUeWtv4jPs+W9Wxd90tRiYipLs/Q -6vwYhTpqgSUh6mUARrRbrL2wRXlfqZEuDsAF+vEEYc3w/6zf84R3B/TLNVholddS -kTIteUz3YJ9cD99anauu7lYEK9h5RMUH81ubRHOVKTerK0bMJ1cXpT71xaQ7JORj -kSrzIR7IVPAyV8f73R5OSRk/ClvsItZ35lU1e/WUEep3Zj0eD2qHjn/8GsCnsLPT -eI69e7kDb6kJ+PPLPija0zu3hnd+8d7aT3wI6mZjCqbeLA/2eTCbPK8mpBEMwJ90 -ymZ8KOQhAgMBAAECggEAegZNO3QsBjaUpjUZu816teCKq9bTOF4yHweFEabR4G9Q -xdFAPxEn6uQ8eiws7AUnTexoU5625A0LLluNxVcnpInNhExcDU7lPsoubmPE1dap -2NAc04UZ4Q+HiFvFJkNEswiiKMy+Zsidggmv8O89UQXfxovdn60mG5upo97+HqoS -YNxDtCuV1vbyr3n3kT3Hckqs6Rg2i1VTC12v17XfRiPgl13swoYbPh3Rb6x+nkvA -99PEO5941tC7WlpXU1q+t+keBnAbZ8MpErKHeAwwbqO10zxq5ZXQ/q8Po0hTPmD5 -e/UDGeH6NEXoFfoIkFZ4i5Qn3ruxSu+uCO43tY7OAQKBgQD4WPgTOQhhhNm7bDPl -IAR9AOKUiqUrhjk+HgXS5Cmoe0pDOnlIrgtk0PFI+y6liHiSY0xgP7jYmXYYMhyu -CoLkzXSpto4iGB17Vf0Ad9CEH5IYv0GYf9e04wmGwSGAvpP6LRw1BpvkIaOERARC -c/cCB3SxW3ZRlEzhY+nbrqVkjwKBgQDPFSn3m/ZzLdyX/GpfIYDxprIAhDMzVVvQ -dCaJ7WLw+eIXmM4B+fE5dmQPj5n5aCAv4+byZD8SVybRK6FRC9GNA+2oR+2ImAWH -yJ+bKzOW4NrcFHoLOu6+viq/IkdkL/rBga+UShgNOZUMm/5y5X+nxelo4zujcNTr -YwKy6DlkTwKBgG1LalG7Zc7VEqWDJwuNHayNuSm6IpqXBZYqzFFVjGfTaolPsJSl -0+nYcne143+CId36yWAKayUX1HstgqWthpF/Qfp2lvK2PjNLUn7kO+YJptgxQ4MD -sECxMj4VvNLWDHWraKCFehHaJAZPkLhWJLzF3zs2j0mzxGnk+MRvheZNAoGAPgBS -Lmat5VJn58GVf6IiXzfPt8PdKJN4B/OezlEa/Jd0kCgaFhFlnhTKZLZUHY6FhJEx -xoUpNS6O2rW7eO6W8Sep8maGwgzyKvNwhh7rNVNhc99VoyMj9EwvtEZpJaAP7fwM -O9PrW5pP/BSAnJoGHI9vEQ5n/sl7lnZwimxpMpUCgYB5Q3UJLTdt23O/rFVz9HuX -ct2F3TRGA1WdHAH8XIn6lvgi6vGmwVSfRdcVu0uKIIQhQZOK9Bm8K8nn+gBzx8Qe -9n3zs6kNmZYy/V6DB/oYJ+NSEpB9hPZa+otmrrjIlY9q61jvNpnSlkfyBgeODZKW -dbCu3RRO6z6fiMUk49pbrQ== +// Client key (for mTLS) generated with: +// openssl req -newkey rsa:2048 -nodes -keyout client.key -out client.csr -subj "/C=GB/ST=London/L=London/O=libvault consultants/OU=IT Department/CN=*" +const clientKey string = `-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC6MwSpGNZz7sCO +/6Wn+iC7Am+UxQkfm+SWHDxRB9wgDQbZVesAFWiRkMXcTQjBc/71R2RhZed1FFVO +vXZfewfgepdq9RlRCEgFSoMhF8zuwxwKfrrAML2PiRy720i0azwLLilTQB9s5MrB +Cz0Gsq2neY6wXf3KkyMYyhzBaKocl5NqxIcHILWJ+jBnKrfvW69CP8jtIjZLo9xS +WtCw0S2pTVRBt16smiA8VNfXnZc2p8LyWCmZ523AjqKnatviiJ6apyTlhsLMx9Lf +RIqkirgaoTB9y6VFvyZQtqXD+PI7r9QykVgHioMnep2gsJwgxqTuj75gxTsebIJd +PKdv4qwTAgMBAAECggEAUSsWWAR8z/L/PBcThsNR61PngknWbVIO9qT+YjBz9ADZ +wHpkxBeRCwu6RQvLylEfjpr9ljvPB0nC2l1bMco3J9MpGLYZwCpFAxF1UkLG0jp5 +idWu4UMeD2ks/nNcIVIxzYnk9+aXDGg8PqUAiF/xtXUXD6kZjmpPvWm12VYf+fAX +OIXrs3BDJKsJUDfOxg8ujcOuK+qyQjVOoiR8zrREZy/fCRc0TSD7tnnLLPW5MCst +PaFhS8vb35XuTvzCW7yCdosV/xnf2I22KWVJDxV11xtfbi3AF8ggyzUZElW8fVCz +7AJU3W95NVArNw3mvSm6vTcdbddQbuJsMnW1Hc2YCQKBgQDaBUlnliOpTUAGxCOV +sLl7GjsMfH8TrsHa9+ca0BwcoSqDky0jGh/sm1LgyPqoHn9Vj8uK/DLebNMnRZAc +KzGMQpzneW7K0G64SHJI6Faa29FTUfa+azeS3vIKa6WbTWzuhGQ/R7OqTy7UbJTs +IQaA/vfPa13ZNWtHONAaMO96PQKBgQDaoqVVv9NZIVCK1PlcdHhjJ++NrWkKgBGk +YaMvXbWRP0vF1vEgKIE8vzNufQiw6FuiZgeLQluglN6wkvV3fzhVnu7An8DqVaxD +JQQAuwHTvn3wmiepMuYNleYU67bAeFhNZRJuOmkUtrLiPOgVliuwNUqmaaUnzouD +RLzFs/00jwKBgQCLcqI2zUNWAIEZUs7n6bdZU7e9DsxBDKAVrEZ3UfEJJtSIf9R5 +BTayIc7q0+HvMkKDuYuZBCKNPdH45nd8bOwuKFUvgO4qbxLCcCQZGfJ67mp+/ofx +16YeHNd3bs7n/KfWD3wHNZdnMWpkmGbQeXctfueGFchbK93IGkCQ4AfsiQKBgHEH +bsRC9Gd6wqHTcsrqZ6aTadPr14cXKIe79loxbwGVIH46HdRLPG0ER/mR6GFU7rKp +XrMO7kG5VNsiToalnaEeFj49GMXM3s6jn0slYs9uBrvRZjmh168kVJtyNLuSO8xf +OUUFK3gK77XoWO94AEQLePlJWpmWvSdy7MikwX1fAoGALrRIZVmlmDoJ/jm9lNaZ +r3PmRWYlhqLyI/oeEzczqy6WOGcTOQsXlP4Yu1EM6V9mLqQ4ATZ2lUM3mcahfi14 +RPYzuPxqdxxmRGy1iPVWwU7Jw97ke80Zx68Wm69sQHb8Gz9Y6B3c/F63WMuojyas +APnsbr5Kx+5wC0t3xGfShK4= -----END PRIVATE KEY-----` -const caCert string = `-----BEGIN CERTIFICATE----- -MIIDLTCCAhWgAwIBAgIJAOGqv8bs2vsHMA0GCSqGSIb3DQEBCwUAMC0xEzARBgNV -BAoMCmlvLnN0cmltemkxFjAUBgNVBAMMDWNsaWVudHMtY2EgdjAwHhcNMTkwODE5 -MDU1MjI3WhcNMjAwODE4MDU1MjI3WjAtMRMwEQYDVQQKDAppby5zdHJpbXppMRYw -FAYDVQQDDA1jbGllbnRzLWNhIHYwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA62RSy57QNyfIR16c4AzLxGl+HQjX6rGvLzuB6rJt/J4mnPwn0m5i5ubt -QyD1bsdd/hyO8V3yqg8moZ+MEgM6ckiJhlDvO1+/pbUdNwr29vKcBgB0yoTyDrx8 -g2i5vpbbm5Q0cljbtrmD/UzBkTOLpCC+R/HtuwI6ea3iFN8J6u5TlmlFNVLhpzJv -uwwWvW29ryRDtvz60F+YApCv6bJwkL/ZtDkujVqBKCIFT+QFBt/35/EE/tZ7g5WL -kgPcr8d9oA/2LMk1gJIqUyQBL9dlFeKxSl4xLkK8n1xhjHfgn9vtasB2FtuaZ362 -tfkWtARL7M17HVSEa5g9lOIHp2XYswIDAQABo1AwTjAdBgNVHQ4EFgQUqD+5Vwcr -2J2QMJQTxXb9XnB/i6AwHwYDVR0jBBgwFoAUqD+5Vwcr2J2QMJQTxXb9XnB/i6Aw -DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAEuI62DUpQfuI4uz87XlX -N5BbNEe5pqjS6VGE+JkO6SWjyu7S3V7I9Q1C0CfUsqn44xftPWco5T7TcBj5ATpS -GtLPa9B5C7WlP5VrNhyS55BZz2nU0lysXNY59b89cl2fVj+09vIpE9tdYmC/PolL -U1nFGo5xgZJbPVAhCMYyrVebDAKS/aViDSO2CbDlxNN5SUwIoMPd51in49z33vg7 -W+BWYFyufGaDaB2R/BkWxmwPA+6j+uYyb8kMwk3qivVecDrBUuaJQZNfLIElOXWk -bK65qQDFSPn6bXowKNPbNsXwdIaJBdTLkEB98HzpMU+v7xwEQ/4JPyuNgeKJq86v -dA== +// Client cert (for mTLS) generated with: +// openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -extfile <(echo subjectAltName = IP:127.0.0.1) +const clientCert string = `-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgIUZP3uzJrPArjETkLd2SZticeIAeMwDQYJKoZIhvcNAQEL +BQAwDDEKMAgGA1UEAwwBKjAeFw0yMzA4MDIwODU1NTJaFw0zMzA3MzAwODU1NTJa +MHIxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRv +bjEdMBsGA1UECgwUbGlidmF1bHQgY29uc3VsdGFudHMxFjAUBgNVBAsMDUlUIERl +cGFydG1lbnQxCjAIBgNVBAMMASowggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6MwSpGNZz7sCO/6Wn+iC7Am+UxQkfm+SWHDxRB9wgDQbZVesAFWiRkMXc +TQjBc/71R2RhZed1FFVOvXZfewfgepdq9RlRCEgFSoMhF8zuwxwKfrrAML2PiRy7 +20i0azwLLilTQB9s5MrBCz0Gsq2neY6wXf3KkyMYyhzBaKocl5NqxIcHILWJ+jBn +KrfvW69CP8jtIjZLo9xSWtCw0S2pTVRBt16smiA8VNfXnZc2p8LyWCmZ523AjqKn +atviiJ6apyTlhsLMx9LfRIqkirgaoTB9y6VFvyZQtqXD+PI7r9QykVgHioMnep2g +sJwgxqTuj75gxTsebIJdPKdv4qwTAgMBAAGjUzBRMA8GA1UdEQQIMAaHBH8AAAEw +HQYDVR0OBBYEFJXWoxXktt1SPSppKKxG9irVdZ6pMB8GA1UdIwQYMBaAFDfhKgNf +8sL6LaHntwho4aYZlOAHMA0GCSqGSIb3DQEBCwUAA4IBAQAY+8cforOMMqzuyQtm +q2fs+rd/AavSTxxOjazD+QX7vwoCjvSqBSVr53//1hFKoEE33PsQ+UpNVOkYyNo1 +QuyKfhlnqJ7wfXYFWorU07qjHHc02SlQmqHTIpu0VaUxRuEbHdMhO54oJqBnLkL5 +lSOGjsHAMVh/a7ET96OqZKwMwNpWZXLmVhkXkpqf21Ept8P1aweEmmkaW3WAMQ/Y +L99WlvK/Zds/xUlXcpDBOrVZwXuYqhYsjxfig5J6z3bX6o/0g+baL0CRpIz+66BF +Ks1CJYZnOX9Tb26DyBTQAUXzJMv9sJXlYF3Llhd14YfEmOeXnNkog8GflJA7GU6C +lkAS +-----END CERTIFICATE-----` + +// Server key generated with: +// openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr -subj "/C=GB/ST=London/L=London/O=libvault consultants/OU=IT Department/CN=*" +const serverKey string = `-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQClYidsRfhbhwxx +GUZ7X7/CwltfZCof/FmrYqzsWzimr8tUWPy/AHJHo+A08ixuZMBuCn2Uh22gFaEZ +Kn3Uk8ZmGXb9IhYZxTJrYx9+ZUvBaN5g8072bbF2TCCDYhX1w9o488mSVe3vP/I/ +tINuOy990fr1BkhzSoFD/xVhQMqoDN00+B8mIWJ9pstknDcAM+6Z+FfUuwzLcxx5 +LogpOIGhYt+03ywXDxfuvXfRFXFGCwifcLx8XyiOchBckxLtfXioC4Q61gWE63VN +J7qyPDrdUZ/CCY5Vz+qRqsF2rlwOWPluXrWzaKzlvmCm5iQ8J58c6dHhyY8Yob8K +xHo9F56bAgMBAAECggEARgN6Hg+3FwRio4SoPnWoCErghM8yOC1MRs5013C82HAm +m5Q6l5+YQbTiJ3f4kFmNz2gYhucYZUOS2kUPVQ2kWbfhFEO4aHt/n0+s1wUKH5yG +PDP000VX8fVDdGtzUYJy4VZvmMhQ/M6s/wQr+eALeHALFmztAgXiGIemJPBZeu+c +rbAFowzdYsHpTSrh2nm0HYSoyZr87wQoQjLo0c6FqLLxYcnCvMemcg8HK4iw6I0a +vbbG61Pdg4CNy6ZgSS96+WwiixrcWoQ7CN339giRmFT2e6vulbreQtD4QzlmqtWW +su+Du3kc/9XqtJwOpyOkHyXrALMnpPC+c0WnVp76xQKBgQDa/kd79kOWzQXTKmqn +heuaKq/UTMYlGhc13KhEpXeX/r0skWMKjuvxgVacNxv4F4d2axCLmADh1UotZsDz +9Hlvq5aPn8f/VYv0CCwOrigSyv25AEAZCnk84igbiSq1TfXppJzyqYoLue2HrW4k +CHL9KviBwauePNRDv+KNZJGALQKBgQDBVLHMDF6xjsy27T4toqLz1thdiBjd/GR+ +SE6+j18z/CKJVCWlRBykmJ3vxW9qAptdb86ZxmfIFnkWJTt/yEthvyfqHe6ksXED +SElOKuReUYAPJazaGS5F9TywGnsVxhwn9BtqPMy/b7WRQJowcG9zSlntjT+cn7sg +GfSB6ASO5wKBgDaiRXc5ovcWQyPBa0ZL9NFLYP5YAP70mWHIoPovRbzXwp5BzzGt +IlPn7pGedg3Y4OS8JS6OR3oP2ielgPHbxggECNXgCOc8kmPZPhSTgk/d8Jqc42Db +6g80ZMkp2UvOHVGizb0Eavot8oJs1BONQBLFC6ZjiMs7ZcFZN84KjvopAoGAYPAz +ummVbZh5o1tv6vf6lyNqF/Pu7Bfq17sv6LMA/JL3Sj6sJaLybcGsp5Yq2E/4UTCH +umlWjmheTLFclST8T0XHIMfjaici0I+FWjF9kqFxAadVdYJcxm1CAdc1UmSkp4/p +0yorS+4ab3uiFJm7+GYWk1tYwxMAhAcfp6eL6Y8CgYAMNptHbD/fL0wrXDBVWRYP +LL55dHKf6Op+c2N9/82WsaMpHQ/A8MiIn2iwQReEIjl0zk+OfvTgQEz1FEw+zZk/ +kFWRLF8Hel5mv0JKz8ExZ4LHTTE8OpxvEbvP3j6A/MngpsuN73LA4i/GqrktGtiy +UYF0gdXCSiPfvXct5lwU7g== +-----END PRIVATE KEY-----` + +// Server cert generated with: +// openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -extfile <(echo subjectAltName = IP:127.0.0.1) +const serverCert string = `-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgIUZGbRxIm/HK0OiVdTzIFWmnPqttUwDQYJKoZIhvcNAQEL +BQAwDDEKMAgGA1UEAwwBKjAeFw0yMzA4MDIwODU0NTlaFw0zMzA3MzAwODU0NTla +MHIxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRv +bjEdMBsGA1UECgwUbGlidmF1bHQgY29uc3VsdGFudHMxFjAUBgNVBAsMDUlUIERl +cGFydG1lbnQxCjAIBgNVBAMMASowggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQClYidsRfhbhwxxGUZ7X7/CwltfZCof/FmrYqzsWzimr8tUWPy/AHJHo+A0 +8ixuZMBuCn2Uh22gFaEZKn3Uk8ZmGXb9IhYZxTJrYx9+ZUvBaN5g8072bbF2TCCD +YhX1w9o488mSVe3vP/I/tINuOy990fr1BkhzSoFD/xVhQMqoDN00+B8mIWJ9pstk +nDcAM+6Z+FfUuwzLcxx5LogpOIGhYt+03ywXDxfuvXfRFXFGCwifcLx8XyiOchBc +kxLtfXioC4Q61gWE63VNJ7qyPDrdUZ/CCY5Vz+qRqsF2rlwOWPluXrWzaKzlvmCm +5iQ8J58c6dHhyY8Yob8KxHo9F56bAgMBAAGjUzBRMA8GA1UdEQQIMAaHBH8AAAEw +HQYDVR0OBBYEFOdbqIlktmQGpRr9ydKkACwx/OnhMB8GA1UdIwQYMBaAFDfhKgNf +8sL6LaHntwho4aYZlOAHMA0GCSqGSIb3DQEBCwUAA4IBAQAMKfFetofRb9dFInU5 +KpF3+IVwrR53UbUbNF0mnQ7aNRE7YfLPRTOV2Dp5zeOlUiO6FhK1AkCcs1RILzUM +bUwolEbgQRmMV8NPyY+0vkBQDJQYfw3bHm2NCWRKd2A0KI9rX1VpWvY3Z300zmLM +TPgRGwN4oZbQLpbI6iZ+MuaBw9c3xOuVKGI0OQybl7MM49Uk/QAf+Ltb+VD/b+NR +QtOnsqqqb3s8LlqTbYn1zM9FSX2YNRljDkElTVfzhlD2qpMvy8Ep8qrAlFcI8yZ8 +HKUIvMe6pjPWHHGVkKBldRqQIOH5WoUSKjrC8koV+Kqj6PMXKquyZdvdC3bhgj4l +Pnib -----END CERTIFICATE-----` // CreateCACert returns paths to CA cert and the cleanup function to defer @@ -83,17 +146,17 @@ func CreateCACert(t *testing.T) (string, func()) { return name, cleanup } -// CreateAllCerts returns paths to: +// CreateClientCerts returns paths to: // - ca // - user cert // - user key // and the cleanup function to defer -func CreateAllCerts(t *testing.T) (string, string, string, func()) { +func CreateClientCerts(t *testing.T) (string, string, string, func()) { ca, cleanupCA, err := DumpToTemp(caCert) require.NoError(t, err) - uc, cleanupUC, err := DumpToTemp(userCert) + uc, cleanupUC, err := DumpToTemp(clientCert) require.NoError(t, err) - uk, cleanupUK, err := DumpToTemp(userKey) + uk, cleanupUK, err := DumpToTemp(clientKey) require.NoError(t, err) return ca, uc, uk, func() { cleanupCA() @@ -101,3 +164,30 @@ func CreateAllCerts(t *testing.T) (string, string, string, func()) { cleanupUK() } } + +// CreateAllCerts returns paths to: +// - ca +// - user cert +// - user key +// - server cert +// - server key +// and the cleanup function to defer +func CreateAllCerts(t *testing.T) (string, string, string, string, string, func()) { + ca, cleanupCA, err := DumpToTemp(caCert) + require.NoError(t, err) + uc, cleanupUC, err := DumpToTemp(clientCert) + require.NoError(t, err) + uk, cleanupUK, err := DumpToTemp(clientKey) + require.NoError(t, err) + sc, cleanupSC, err := DumpToTemp(serverCert) + require.NoError(t, err) + sk, cleanupSK, err := DumpToTemp(serverKey) + require.NoError(t, err) + return ca, uc, uk, sc, sk, func() { + cleanupCA() + cleanupUC() + cleanupUK() + cleanupSC() + cleanupSK() + } +} diff --git a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/grpc/flow/client.go b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/grpc/flow/client.go index 350bc619b..6049f243e 100644 --- a/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/grpc/flow/client.go +++ b/vendor/github.com/netobserv/netobserv-ebpf-agent/pkg/grpc/flow/client.go @@ -2,23 +2,60 @@ package flowgrpc import ( + "crypto/tls" + "crypto/x509" + "fmt" + "os" + "github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow" "github.com/netobserv/netobserv-ebpf-agent/pkg/utils" + "github.com/sirupsen/logrus" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" ) +var clog = logrus.WithField("component", "grpc.Client") + // ClientConnection wraps a gRPC+protobuf connection type ClientConnection struct { client pbflow.CollectorClient conn *grpc.ClientConn } -func ConnectClient(hostIP string, hostPort int) (*ClientConnection, error) { - // TODO: allow configuring some options (keepalive, backoff...) +func ConnectClient(hostIP string, hostPort int, caPath, userCertPath, userKeyPath string) (*ClientConnection, error) { + // TODO: allow configuring more options (keepalive, backoff...) + var opts []grpc.DialOption + if caPath == "" { + clog.Info("Starting GRPC client - no TLS") + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } else { + // Configure TLS (server CA) + caCert, err := os.ReadFile(caPath) + if err != nil { + return nil, fmt.Errorf("Cannot load CA certificate: %w", err) + } + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(caCert) + tlsConfig := &tls.Config{ + RootCAs: pool, + } + if userCertPath != "" && userKeyPath != "" { + clog.Info("Starting GRPC client with mTLS") + // Configure mTLS (client certificates) + cert, err := tls.LoadX509KeyPair(userCertPath, userKeyPath) + if err != nil { + return nil, fmt.Errorf("Cannot load client certificate: %w", err) + } + tlsConfig.Certificates = []tls.Certificate{cert} + } else { + clog.Info("Starting GRPC client with TLS") + } + + opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) + } socket := utils.GetSocket(hostIP, hostPort) - conn, err := grpc.NewClient(socket, - grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.NewClient(socket, opts...) if err != nil { return nil, err } diff --git a/vendor/modules.txt b/vendor/modules.txt index 8433f5117..7a74116ed 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -306,7 +306,7 @@ github.com/netobserv/loki-client-go/pkg/logproto github.com/netobserv/loki-client-go/pkg/metric github.com/netobserv/loki-client-go/pkg/metrics github.com/netobserv/loki-client-go/pkg/urlutil -# github.com/netobserv/netobserv-ebpf-agent v1.10.0-community.0.20251125162210-4be10c36721e +# github.com/netobserv/netobserv-ebpf-agent v1.10.0-community.0.20251125162210-4be10c36721e => github.com/jotak/netobserv-agent v0.0.0-20251201132656-d1dee7de8bca ## explicit; go 1.24.0 github.com/netobserv/netobserv-ebpf-agent/pkg/decode github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf @@ -1392,3 +1392,4 @@ sigs.k8s.io/structured-merge-diff/v6/value sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 # github.com/vmware/go-ipfix => github.com/jotak/go-ipfix v0.0.0-20250708115123-407c539ea101 +# github.com/netobserv/netobserv-ebpf-agent => github.com/jotak/netobserv-agent v0.0.0-20251201132656-d1dee7de8bca