Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable CORS settings on OTLP HTTP endpoint #4586

Merged
merged 3 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cmd/collector/app/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,7 @@ func (c *Collector) Start(options *flags.CollectorOptions) error {
Handler: c.spanHandlers.ZipkinSpansHandler,
TLSConfig: options.Zipkin.TLS,
HealthCheck: c.hCheck,
AllowedHeaders: options.Zipkin.AllowedHeaders,
AllowedOrigins: options.Zipkin.AllowedOrigins,
CORSConfig: options.Zipkin.CORS,
Logger: c.logger,
MetricsFactory: c.metricsFactory,
KeepAlive: options.Zipkin.KeepAlive,
Expand Down
27 changes: 17 additions & 10 deletions cmd/collector/app/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"go.uber.org/zap"

"github.com/jaegertracing/jaeger/cmd/flags"
"github.com/jaegertracing/jaeger/pkg/config/corscfg"
"github.com/jaegertracing/jaeger/pkg/config/tlscfg"
"github.com/jaegertracing/jaeger/pkg/tenancy"
"github.com/jaegertracing/jaeger/ports"
Expand All @@ -49,8 +50,6 @@ const (
flagCollectorOTLPEnabled = "collector.otlp.enabled"

flagZipkinHTTPHostPort = "collector.zipkin.host-port"
flagZipkinAllowedHeaders = "collector.zipkin.allowed-headers"
flagZipkinAllowedOrigins = "collector.zipkin.allowed-origins"
flagZipkinKeepAliveEnabled = "collector.zipkin.keep-alive"

// DefaultNumWorkers is the default number of workers consuming from the processor queue
Expand Down Expand Up @@ -99,6 +98,14 @@ var tlsZipkinFlagsConfig = tlscfg.ServerFlagsConfig{
Prefix: "collector.zipkin",
}

var corsZipkinFlags = corscfg.Flags{
Prefix: "collector.zipkin",
}

var corsOTLPFlags = corscfg.Flags{
Prefix: "collector.otlp.http",
}

// CollectorOptions holds configuration for collector
type CollectorOptions struct {
// DynQueueSizeMemory determines how much memory to use for the queue
Expand All @@ -121,12 +128,10 @@ type CollectorOptions struct {
Zipkin struct {
// HTTPHostPort is the host:port address that the Zipkin collector service listens in on for http requests
HTTPHostPort string
// ZipkinAllowedOrigins is a list of origins a cross-domain request to the Zipkin collector service can be executed from
AllowedOrigins string
// ZipkinAllowedHeaders is a list of headers that the Zipkin collector service allowes the client to use with cross-domain requests
AllowedHeaders string
// TLS configures secure transport for Zipkin endpoint to collect spans
TLS tlscfg.Options
// CORS allows CORS requests , sets the values for Allowed Headers and Allowed Origins.
CORS corscfg.Options
// KeepAlive configures allow Keep-Alive for Zipkin HTTP server
KeepAlive bool
}
Expand All @@ -153,6 +158,8 @@ type HTTPOptions struct {
ReadHeaderTimeout time.Duration
// IdleTimeout sets the respective parameter of http.Server
IdleTimeout time.Duration
// CORS allows CORS requests , sets the values for Allowed Headers and Allowed Origins.
CORS corscfg.Options
}

// GRPCOptions defines options for a gRPC server
Expand Down Expand Up @@ -186,13 +193,13 @@ func AddFlags(flags *flag.FlagSet) {

flags.Bool(flagCollectorOTLPEnabled, true, "Enables OpenTelemetry OTLP receiver on dedicated HTTP and gRPC ports")
addHTTPFlags(flags, otlpServerFlagsCfg.HTTP, "")
corsOTLPFlags.AddFlags(flags)
addGRPCFlags(flags, otlpServerFlagsCfg.GRPC, "")

flags.String(flagZipkinAllowedHeaders, "content-type", "Comma separated list of allowed headers for the Zipkin collector service, default content-type")
flags.String(flagZipkinAllowedOrigins, "*", "Comma separated list of allowed origins for the Zipkin collector service, default accepts all")
flags.String(flagZipkinHTTPHostPort, "", "The host:port (e.g. 127.0.0.1:9411 or :9411) of the collector's Zipkin server (disabled by default)")
flags.Bool(flagZipkinKeepAliveEnabled, true, "KeepAlive configures allow Keep-Alive for Zipkin HTTP server (enabled by default)")
tlsZipkinFlagsConfig.AddFlags(flags)
corsZipkinFlags.AddFlags(flags)

tenancy.AddFlags(flags)
}
Expand Down Expand Up @@ -273,19 +280,19 @@ func (cOpts *CollectorOptions) InitFromViper(v *viper.Viper, logger *zap.Logger)
if err := cOpts.OTLP.HTTP.initFromViper(v, logger, otlpServerFlagsCfg.HTTP); err != nil {
return cOpts, fmt.Errorf("failed to parse OTLP/HTTP server options: %w", err)
}
cOpts.OTLP.HTTP.CORS = corsOTLPFlags.InitFromViper(v)
if err := cOpts.OTLP.GRPC.initFromViper(v, logger, otlpServerFlagsCfg.GRPC); err != nil {
return cOpts, fmt.Errorf("failed to parse OTLP/gRPC server options: %w", err)
}

cOpts.Zipkin.AllowedHeaders = v.GetString(flagZipkinAllowedHeaders)
cOpts.Zipkin.AllowedOrigins = v.GetString(flagZipkinAllowedOrigins)
cOpts.Zipkin.KeepAlive = v.GetBool(flagZipkinKeepAliveEnabled)
cOpts.Zipkin.HTTPHostPort = ports.FormatHostPort(v.GetString(flagZipkinHTTPHostPort))
if tlsZipkin, err := tlsZipkinFlagsConfig.InitFromViper(v); err == nil {
cOpts.Zipkin.TLS = tlsZipkin
} else {
return cOpts, fmt.Errorf("failed to parse Zipkin TLS options: %w", err)
}
cOpts.Zipkin.CORS = corsZipkinFlags.InitFromViper(v)

return cOpts, nil
}
5 changes: 5 additions & 0 deletions cmd/collector/app/handler/otlp_receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ func applyHTTPSettings(cfg *confighttp.HTTPServerSettings, opts *flags.HTTPOptio
if opts.TLS.Enabled {
cfg.TLSSetting = applyTLSSettings(&opts.TLS)
}

cfg.CORS = &confighttp.CORSSettings{
AllowedOrigins: opts.CORS.AllowedOrigins,
AllowedHeaders: opts.CORS.AllowedHeaders,
}
}

func applyTLSSettings(opts *tlscfg.Options) *configtls.TLSServerSetting {
Expand Down
8 changes: 8 additions & 0 deletions cmd/collector/app/handler/otlp_receiver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

"github.com/jaegertracing/jaeger/cmd/collector/app/flags"
"github.com/jaegertracing/jaeger/model"
"github.com/jaegertracing/jaeger/pkg/config/corscfg"
"github.com/jaegertracing/jaeger/pkg/config/tlscfg"
"github.com/jaegertracing/jaeger/pkg/tenancy"
"github.com/jaegertracing/jaeger/pkg/testutils"
Expand Down Expand Up @@ -204,11 +205,16 @@ func TestApplyOTLPHTTPServerSettings(t *testing.T) {
MinVersion: "1.1",
MaxVersion: "1.3",
},
CORS: corscfg.Options{
AllowedOrigins: []string{"http://example.domain.com", "http://*.domain.com"},
AllowedHeaders: []string{"Content-Type", "Accept", "X-Requested-With"},
},
}

applyHTTPSettings(otlpReceiverConfig.HTTP, httpOpts)

out := otlpReceiverConfig.HTTP

assert.Equal(t, out.Endpoint, ":12345")
require.NotNil(t, out.TLSSetting)
assert.Equal(t, out.TLSSetting.CAFile, "ca")
Expand All @@ -217,4 +223,6 @@ func TestApplyOTLPHTTPServerSettings(t *testing.T) {
assert.Equal(t, out.TLSSetting.ClientCAFile, "clientca")
assert.Equal(t, out.TLSSetting.MinVersion, "1.1")
assert.Equal(t, out.TLSSetting.MaxVersion, "1.3")
assert.Equal(t, out.CORS.AllowedHeaders, []string{"Content-Type", "Accept", "X-Requested-With"})
assert.Equal(t, out.CORS.AllowedOrigins, []string{"http://example.domain.com", "http://*.domain.com"})
}
12 changes: 4 additions & 8 deletions cmd/collector/app/server/zipkin.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package server
import (
"net"
"net/http"
"strings"
"time"

"github.com/gorilla/mux"
Expand All @@ -27,6 +26,7 @@ import (

"github.com/jaegertracing/jaeger/cmd/collector/app/handler"
"github.com/jaegertracing/jaeger/cmd/collector/app/zipkin"
"github.com/jaegertracing/jaeger/pkg/config/corscfg"
"github.com/jaegertracing/jaeger/pkg/config/tlscfg"
"github.com/jaegertracing/jaeger/pkg/healthcheck"
"github.com/jaegertracing/jaeger/pkg/httpmetrics"
Expand All @@ -39,8 +39,7 @@ type ZipkinServerParams struct {
TLSConfig tlscfg.Options
HostPort string
Handler handler.ZipkinSpansHandler
AllowedOrigins string
AllowedHeaders string
CORSConfig corscfg.Options
HealthCheck *healthcheck.HealthCheck
Logger *zap.Logger
MetricsFactory metrics.Factory
Expand Down Expand Up @@ -86,13 +85,10 @@ func serveZipkin(server *http.Server, listener net.Listener, params *ZipkinServe
zHandler := zipkin.NewAPIHandler(params.Handler)
zHandler.RegisterRoutes(r)

origins := strings.Split(strings.ReplaceAll(params.AllowedOrigins, " ", ""), ",")
headers := strings.Split(strings.ReplaceAll(params.AllowedHeaders, " ", ""), ",")

cors := cors.New(cors.Options{
AllowedOrigins: origins,
AllowedOrigins: params.CORSConfig.AllowedOrigins,
AllowedMethods: []string{"POST"}, // Allowing only POST, because that's the only handled one
AllowedHeaders: headers,
AllowedHeaders: params.CORSConfig.AllowedHeaders,
})

recoveryHandler := recoveryhandler.NewRecoveryHandler(params.Logger, true)
Expand Down
49 changes: 49 additions & 0 deletions pkg/config/corscfg/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2023 The Jaeger Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package corscfg

import (
"flag"
"strings"

"github.com/spf13/viper"
)

const (
corsPrefix = ".cors"
corsAllowedHeaders = corsPrefix + ".allowed-headers"
corsAllowedOrigins = corsPrefix + ".allowed-origins"
)

type Flags struct {
Prefix string
}

func (c Flags) AddFlags(flags *flag.FlagSet) {
flags.String(c.Prefix+corsAllowedHeaders, "", "Comma-separated CORS allowed headers. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers")
flags.String(c.Prefix+corsAllowedOrigins, "", "Comma-separated CORS allowed origins. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin")
}

func (c Flags) InitFromViper(v *viper.Viper) Options {
var p Options

allowedHeaders := v.GetString(c.Prefix + corsAllowedHeaders)
allowedOrigins := v.GetString(c.Prefix + corsAllowedOrigins)

p.AllowedOrigins = strings.Split(strings.ReplaceAll(allowedOrigins, " ", ""), ",")
p.AllowedHeaders = strings.Split(strings.ReplaceAll(allowedHeaders, " ", ""), ",")

return p
}
49 changes: 49 additions & 0 deletions pkg/config/corscfg/flags_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2023 The Jaeger Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package corscfg

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/jaegertracing/jaeger/pkg/config"
)

func TestCORSFlags(t *testing.T) {
cmdFlags := []string{
"--prefix.cors.allowed-headers=Content-Type, Accept, X-Requested-With",
"--prefix.cors.allowed-origins=http://example.domain.com, http://*.domain.com",
}
t.Run("CORS Flags", func(t *testing.T) {
flagCfg := Flags{
Prefix: "prefix",
}
v, command := config.Viperize(flagCfg.AddFlags)

err := command.ParseFlags(cmdFlags)
require.NoError(t, err)

corsOpts := flagCfg.InitFromViper(v)
fmt.Println(corsOpts)

assert.Equal(t, Options{
AllowedHeaders: []string{"Content-Type", "Accept", "X-Requested-With"},
AllowedOrigins: []string{"http://example.domain.com", "http://*.domain.com"},
}, corsOpts)
})
}
20 changes: 20 additions & 0 deletions pkg/config/corscfg/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) 2023 The Jaeger Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package corscfg

type Options struct {
AllowedOrigins []string
AllowedHeaders []string
}