diff --git a/server/cmd/api/main.go b/server/cmd/api/main.go index 19a62089..57c3f268 100644 --- a/server/cmd/api/main.go +++ b/server/cmd/api/main.go @@ -140,9 +140,12 @@ func main() { var otlpExporter api.OTLPExporter var otlpMetrics *events.OTLPMetrics if config.OTLPEndpoint != "" { + // The relay authenticates the VM by its instance name (checked against + // active sessions), mirroring the capmonster/hcaptcha relays. Sent as + // x-api-key, not a bearer token. headers := map[string]string{} - if config.InstanceJWT != "" { - headers["Authorization"] = "Bearer " + config.InstanceJWT + if config.InstanceName != "" { + headers["x-api-key"] = config.InstanceName } slogger.Info("OTLP export available", "endpoint", config.OTLPEndpoint, "path", config.OTLPPath) // The OTel log SDK reports batch-queue drops through its global logger at diff --git a/server/cmd/config/config.go b/server/cmd/config/config.go index 70cce914..74b210c7 100644 --- a/server/cmd/config/config.go +++ b/server/cmd/config/config.go @@ -70,11 +70,11 @@ type Config struct { OTLPMaxQueueSize int `envconfig:"BTEL_OTLP_MAX_QUEUE_SIZE" default:"2048"` OTLPExportInterval time.Duration `envconfig:"BTEL_OTLP_EXPORT_INTERVAL" default:"1s"` OTLPExportTimeout time.Duration `envconfig:"BTEL_OTLP_EXPORT_TIMEOUT" default:"30s"` - // Platform-injected identity, reused to stamp the OTLP Resource. These are - // the same envs the VM already receives. - InstanceJWT string `envconfig:"KERNEL_INSTANCE_JWT" default:""` - InstanceName string `envconfig:"INST_NAME" default:""` - MetroName string `envconfig:"METRO_NAME" default:""` + // Platform-injected identity: InstanceName is sent to the relay as x-api-key + // and, with MetroName, stamps the OTLP Resource. Same envs the VM already + // receives. + InstanceName string `envconfig:"INST_NAME" default:""` + MetroName string `envconfig:"METRO_NAME" default:""` } // LogValue implements slog.LogValuer, redacting secret fields. @@ -83,10 +83,6 @@ func (c *Config) LogValue() slog.Value { if c.S2AccessToken != "" { s2AccessToken = "[redacted]" } - otlpJWT := "" - if c.InstanceJWT != "" { - otlpJWT = "[redacted]" - } return slog.GroupValue( slog.Int("port", c.Port), slog.Int("metrics_port", c.MetricsPort), @@ -109,7 +105,6 @@ func (c *Config) LogValue() slog.Value { slog.String("otlp_endpoint", c.OTLPEndpoint), slog.String("otlp_path", c.OTLPPath), slog.Bool("otlp_insecure", c.OTLPInsecure), - slog.String("otlp_instance_jwt", otlpJWT), slog.String("otlp_service_name", c.OTLPServiceName), slog.Int("otlp_max_queue_size", c.OTLPMaxQueueSize), slog.Duration("otlp_export_interval", c.OTLPExportInterval), diff --git a/server/lib/events/otlpstorage_test.go b/server/lib/events/otlpstorage_test.go index 50eecc8e..b33aabcf 100644 --- a/server/lib/events/otlpstorage_test.go +++ b/server/lib/events/otlpstorage_test.go @@ -51,7 +51,7 @@ func TestLoggingExporter_CountsExportFailures(t *testing.T) { // that an excluded category (screenshot) never reaches the receiver. func TestOTLPStorageWriter_ExportsEvents(t *testing.T) { var mu sync.Mutex - var paths, auths, eventNames []string + var paths, apiKeys, eventNames []string attrStr := map[string]string{} var statusAttr int64 var bodyIsMap bool @@ -62,7 +62,7 @@ func TestOTLPStorageWriter_ExportsEvents(t *testing.T) { require.NoError(t, proto.Unmarshal(body, &req)) mu.Lock() paths = append(paths, r.URL.Path) - auths = append(auths, r.Header.Get("Authorization")) + apiKeys = append(apiKeys, r.Header.Get("x-api-key")) for _, rl := range req.ResourceLogs { for _, sl := range rl.ScopeLogs { for _, lr := range sl.LogRecords { @@ -92,7 +92,7 @@ func TestOTLPStorageWriter_ExportsEvents(t *testing.T) { Endpoint: strings.TrimPrefix(srv.URL, "http://"), URLPath: "/otlp-relay/v1/logs", Insecure: true, - Headers: map[string]string{"Authorization": "Bearer test-jwt"}, + Headers: map[string]string{"x-api-key": "browser-1"}, ServiceName: "kernel-browser", InstanceName: "browser-1", Metro: "dev-iad", @@ -115,7 +115,8 @@ func TestOTLPStorageWriter_ExportsEvents(t *testing.T) { defer mu.Unlock() require.NotEmpty(t, paths, "expected at least one export request") assert.Equal(t, "/otlp-relay/v1/logs", paths[0]) - assert.Equal(t, "Bearer test-jwt", auths[0]) + // The relay authenticates the VM by instance name sent as x-api-key. + assert.Equal(t, "browser-1", apiKeys[0]) // The excluded screenshot must not reach the receiver; only the network event does. assert.Equal(t, []string{"network_response"}, eventNames) // Promoted attributes and the structured body survive the SDK to protobuf translation.