Skip to content

Commit 28feb3c

Browse files
authored
Merge pull request #397 from Andreagit97/fix-otel-grpc
fix: correctly handle both grpc and http
2 parents 5cac169 + 69ea60f commit 28feb3c

7 files changed

Lines changed: 104 additions & 20 deletions

File tree

charts/runtime-enforcer/templates/agent/daemonset.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,15 @@ spec:
5757
{{- if eq .Values.telemetry.collectorStrategy "default" }}
5858
- name: OTEL_EXPORTER_OTLP_ENDPOINT
5959
value: https://{{ include "runtime-enforcer.fullname" . }}-otel-collector.{{ .Release.Namespace }}.svc.cluster.local:4317
60+
- name: OTEL_EXPORTER_OTLP_PROTOCOL
61+
value: grpc
6062
- name: OTEL_EXPORTER_OTLP_CERTIFICATE
6163
value: {{ include "runtime-enforcer.grpc.certDir" . }}/ca.crt
6264
{{- else if eq .Values.telemetry.collectorStrategy "external" }}
6365
- name: OTEL_EXPORTER_OTLP_ENDPOINT
6466
value: {{ .Values.telemetry.externalCollector.endpoint }}
67+
- name: OTEL_EXPORTER_OTLP_PROTOCOL
68+
value: {{ .Values.telemetry.externalCollector.protocol }}
6569
{{- if .Values.telemetry.externalCollector.otelCollectorCertificateSecret }}
6670
- name: OTEL_EXPORTER_OTLP_CERTIFICATE
6771
value: /tmp/otel-collector-certs/ca.crt

charts/runtime-enforcer/values.schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,13 @@
435435
},
436436
"otelCollectorClientCertificateSecret": {
437437
"type": "string"
438+
},
439+
"protocol": {
440+
"type": "string",
441+
"enum": [
442+
"grpc",
443+
"http/protobuf"
444+
]
438445
}
439446
},
440447
"additionalProperties": false

charts/runtime-enforcer/values.yaml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,15 @@ telemetry:
168168
cpu: 10m
169169
memory: 64Mi
170170
externalCollector:
171-
# telemetry.externalCollector.endpoint is the Otel collector endpoint to send metrics and
172-
# traces to. It should be in the format https://<hostname>:<port>.
171+
# telemetry.externalCollector.endpoint is the Otel collector endpoint to send signals to.
172+
# For gRPC, it should be in the format <hostname>:<port>.
173+
# For HTTP, it should be in the format http(s)://<hostname>:<port>.
173174
endpoint: ""
175+
# telemetry.externalCollector.protocol is the protocol to use for the Otel collector.
176+
protocol: "grpc" # @schema enum: [grpc, http/protobuf]
174177
# The following settings are required to configure the OpenTelemetry exporter
175-
# in the controller and policy server to send metrics and traces to a remote
176-
# collector using TLS. Both secrets must be created in the same namespace
177-
# where the controller is deployed.
178+
# to send signals and to a remote collector using TLS.
179+
# Both secrets must be created in the same namespace where the controller is deployed.
178180
#
179181
# If otelCollectorCertificateSecret is not set, TLS verification is disabled
180182
# (insecure mode). When set, the certificate is used to validate the remote

cmd/agent/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type Config struct {
4242
grpcConf grpcexporter.Config
4343
logLevel string
4444
otlpEndpoint string
45+
otlpProtocol string
4546
otlpCACert string
4647
otlpClientCert string
4748
otlpClientKey string
@@ -326,6 +327,8 @@ func parseFlags() Config {
326327
)
327328
flag.StringVar(&config.nodeName, "node-name", os.Getenv("NODE_NAME"),
328329
"Node name for violation reporting (defaults to NODE_NAME env var)")
330+
flag.StringVar(&config.otlpProtocol, "otlp-protocol", os.Getenv("OTEL_EXPORTER_OTLP_PROTOCOL"),
331+
"OTLP protocol (defaults to OTEL_EXPORTER_OTLP_PROTOCOL env var)")
329332
flag.Parse()
330333
return config
331334
}
@@ -350,6 +353,7 @@ func main() {
350353
config.otlpCACert,
351354
config.otlpClientCert,
352355
config.otlpClientKey,
356+
config.otlpProtocol,
353357
)
354358
if err != nil {
355359
slogger.ErrorContext(ctx, "failed to initiate violation event pipeline", "error", err)

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ require (
1313
github.com/stretchr/testify v1.11.1
1414
go.opentelemetry.io/otel v1.42.0
1515
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0
16-
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0
16+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0
1717
go.opentelemetry.io/otel/log v0.18.0
18-
go.opentelemetry.io/otel/sdk v1.42.0
1918
go.opentelemetry.io/otel/sdk/log v0.18.0
2019
go.opentelemetry.io/otel/trace v1.42.0
2120
golang.org/x/sync v0.20.0
@@ -89,7 +88,9 @@ require (
8988
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
9089
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
9190
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect
91+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect
9292
go.opentelemetry.io/otel/metric v1.42.0 // indirect
93+
go.opentelemetry.io/otel/sdk v1.42.0 // indirect
9394
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
9495
go.yaml.in/yaml/v2 v2.4.3 // indirect
9596
go.yaml.in/yaml/v3 v3.0.4 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
193193
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
194194
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY=
195195
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU=
196+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 h1:icqq3Z34UrEFk2u+HMhTtRsvo7Ues+eiJVjaJt62njs=
197+
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0/go.mod h1:W2m8P+d5Wn5kipj4/xmbt9uMqezEKfBjzVJadfABSBE=
196198
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw=
197199
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw=
198200
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto=

internal/events/events.go

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,34 @@ import (
55
"crypto/tls"
66
"crypto/x509"
77
"fmt"
8+
"strings"
89

910
"github.com/rancher-sandbox/runtime-enforcer/internal/tlsutil"
1011
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc"
12+
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
1113
otellog "go.opentelemetry.io/otel/log"
1214
sdklog "go.opentelemetry.io/otel/sdk/log"
1315
"google.golang.org/grpc/credentials"
1416
)
1517

18+
type protocol string
19+
20+
const (
21+
protocolGRPC protocol = "grpc"
22+
protocolHTTPProtobuf protocol = "http/protobuf"
23+
)
24+
25+
func stringToProtocol(s string) (protocol, error) {
26+
switch s {
27+
case "grpc":
28+
return protocolGRPC, nil
29+
case "http/protobuf":
30+
return protocolHTTPProtobuf, nil
31+
default:
32+
return "", fmt.Errorf("unsupported protocol: %s", s)
33+
}
34+
}
35+
1636
func buildTLSConfig(caCertPath, clientCertPath, clientKeyPath string) (*tls.Config, error) {
1737
// Validate that the CA certificate is readable at startup.
1838
if _, err := tlsutil.LoadCACertPool(caCertPath); err != nil {
@@ -50,28 +70,72 @@ func buildTLSConfig(caCertPath, clientCertPath, clientKeyPath string) (*tls.Conf
5070
return cfg, nil
5171
}
5272

53-
// Init creates an OTEL log provider that exports violation events to the given
54-
// gRPC endpoint over TLS. When caCertPath is non-empty, the connection verifies
55-
// the collector's certificate against the provided CA; otherwise the system
56-
// certificate pool is used. When clientCertPath and clientKeyPath are both
57-
// non-empty, the client presents a TLS certificate for mTLS authentication.
58-
func Init(
59-
ctx context.Context,
73+
func createGRPCExporter(ctx context.Context,
6074
endpoint, caCertPath, clientCertPath, clientKeyPath string,
61-
) (otellog.Logger, func(context.Context) error, error) {
75+
) (sdklog.Exporter, error) {
76+
// if the user specified the correct path we shouldn't receive the http prefix here, but just to be sure.
77+
gRPCEndpoint := strings.TrimPrefix(strings.TrimPrefix(endpoint, "https://"), "http://")
78+
insecure := caCertPath == ""
6279
opts := []otlploggrpc.Option{
63-
otlploggrpc.WithEndpointURL(endpoint),
80+
otlploggrpc.WithEndpoint(gRPCEndpoint),
6481
}
65-
66-
if caCertPath != "" {
82+
if insecure {
83+
opts = append(opts, otlploggrpc.WithInsecure())
84+
} else {
6785
tlsConfig, err := buildTLSConfig(caCertPath, clientCertPath, clientKeyPath)
6886
if err != nil {
69-
return nil, nil, err
87+
return nil, err
7088
}
7189
opts = append(opts, otlploggrpc.WithTLSCredentials(credentials.NewTLS(tlsConfig)))
7290
}
91+
return otlploggrpc.New(ctx, opts...)
92+
}
93+
94+
func createHTTPExporter(ctx context.Context,
95+
endpoint, caCertPath, clientCertPath, clientKeyPath string,
96+
) (sdklog.Exporter, error) {
97+
// first we check if we are in insecure mode
98+
insecure := strings.HasPrefix(endpoint, "http://")
99+
// Strip the scheme from the endpoint: WithEndpoint expects "host:port".
100+
httpEndpoint := strings.TrimPrefix(strings.TrimPrefix(endpoint, "https://"), "http://")
73101

74-
exporter, err := otlploggrpc.New(ctx, opts...)
102+
opts := []otlploghttp.Option{
103+
otlploghttp.WithEndpoint(httpEndpoint),
104+
}
105+
106+
if insecure {
107+
opts = append(opts, otlploghttp.WithInsecure())
108+
} else if caCertPath != "" {
109+
tlsConfig, err := buildTLSConfig(caCertPath, clientCertPath, clientKeyPath)
110+
if err != nil {
111+
return nil, err
112+
}
113+
opts = append(opts, otlploghttp.WithTLSClientConfig(tlsConfig))
114+
}
115+
return otlploghttp.New(ctx, opts...)
116+
}
117+
118+
// Init creates an OTEL log provider that exports violation events to the given
119+
// endpoint. The protocol can be either "grpc" or "http/protobuf".
120+
// When caCertPath is non-empty, the connection verifies the collector's
121+
// certificate against the provided CA; otherwise insecure mode is used.
122+
// When clientCertPath and clientKeyPath are both non-empty, the client
123+
// presents a TLS certificate for mTLS authentication.
124+
func Init(
125+
ctx context.Context,
126+
endpoint, caCertPath, clientCertPath, clientKeyPath, protocol string,
127+
) (otellog.Logger, func(context.Context) error, error) {
128+
var exporter sdklog.Exporter
129+
proto, err := stringToProtocol(protocol)
130+
if err != nil {
131+
return nil, nil, err
132+
}
133+
switch proto {
134+
case protocolGRPC:
135+
exporter, err = createGRPCExporter(ctx, endpoint, caCertPath, clientCertPath, clientKeyPath)
136+
case protocolHTTPProtobuf:
137+
exporter, err = createHTTPExporter(ctx, endpoint, caCertPath, clientCertPath, clientKeyPath)
138+
}
75139
if err != nil {
76140
return nil, nil, fmt.Errorf("failed to create OTLP log exporter: %w", err)
77141
}

0 commit comments

Comments
 (0)