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

Support for Custom Exporter Authenticators as Extensions #3128

Merged
merged 65 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
3a541b5
Added support for client auth via extensions
pavankrish123 May 7, 2021
604f0e8
clean up
pavankrish123 May 7, 2021
77dbf97
used proper name for authentication
pavankrish123 May 7, 2021
0eacfd4
added proper example
pavankrish123 May 7, 2021
e38a6bc
added search for grpc auth
pavankrish123 May 7, 2021
2d31e3e
clean up
pavankrish123 May 8, 2021
457cdfc
added tests
pavankrish123 May 9, 2021
e878999
fixed typo in doc string
pavankrish123 May 10, 2021
c9ec98d
fixed readme.md
pavankrish123 May 10, 2021
0baa79c
updated PR per comments + added test cases
pavankrish123 May 12, 2021
cc179ca
fixed tests
pavankrish123 May 12, 2021
cf87bbc
fixed go.mod
pavankrish123 May 12, 2021
54a67fe
Merge branch 'master' into client_auth_ext
pavankrish123 May 12, 2021
eff20d5
fixed imports order
pavankrish123 May 12, 2021
9f761cd
modified per latest changes to component apis
pavankrish123 May 12, 2021
930bcf0
clean up
pavankrish123 May 12, 2021
5392bb0
clean up
pavankrish123 May 12, 2021
4a4e580
clean up
pavankrish123 May 12, 2021
343eca9
clean up
pavankrish123 May 12, 2021
8bb7cfc
clean up
pavankrish123 May 12, 2021
1a7e06d
clean up
pavankrish123 May 12, 2021
7654e1c
clean up
pavankrish123 May 12, 2021
731bd19
clean up
pavankrish123 May 12, 2021
972c131
clean up
pavankrish123 May 12, 2021
54db711
1) Removed OAuth client Authenticator to make PR more manageble 2) Ad…
pavankrish123 May 12, 2021
d872d98
fixed import orders
pavankrish123 May 13, 2021
94fa96c
added more verbose description in README
pavankrish123 May 13, 2021
e86d364
Merge branch 'master' into client_auth_ext
pavankrish123 May 13, 2021
8cf8db0
Merge branch 'master' into client_auth_ext
pavankrish123 May 13, 2021
abcc69d
Fixed merge conflicts per latest commit
pavankrish123 May 13, 2021
1356d06
Made following changes per review comments 1) Renamed the Server Auth…
pavankrish123 May 14, 2021
112a3ac
Merge branch 'master' into client_auth_ext
pavankrish123 May 14, 2021
07292d6
fixed per new main changes
pavankrish123 May 14, 2021
3d129dd
fixed errors from goimpi
pavankrish123 May 14, 2021
344d529
fixed comments per suggestions
pavankrish123 May 14, 2021
6315ae8
fixed test case
pavankrish123 May 14, 2021
e1651df
fixed linting
pavankrish123 May 14, 2021
46cb4db
refactored zipkin
pavankrish123 May 14, 2021
73fdba1
refactored prometheusremotewriteexporter
pavankrish123 May 14, 2021
eea54aa
cleanup
pavankrish123 May 14, 2021
01bf264
refactored opencensus exporter
pavankrish123 May 14, 2021
02eb834
moved clients creations to start of exporters
pavankrish123 May 15, 2021
fbbc1a9
cleanup jaeger exporter
pavankrish123 May 15, 2021
72fec3a
cleanup jaeger exporter
pavankrish123 May 15, 2021
d07af8e
cleanup README
pavankrish123 May 15, 2021
2c8a74b
added complete example for bearertoken auth
pavankrish123 May 17, 2021
48efcbf
Merge branch 'master' into client_auth_ext
pavankrish123 May 17, 2021
6d2f927
removed needless refactorings
pavankrish123 May 17, 2021
94c42de
fixed trace receiver
pavankrish123 May 17, 2021
b4a0c1d
Merge branch 'master' into client_auth_ext
pavankrish123 May 17, 2021
d01dacb
Merge branch 'master' into client_auth_ext
pavankrish123 May 18, 2021
7e65d43
use prper NumConsumers
pavankrish123 May 18, 2021
cc79a97
Fixed liniting
pavankrish123 May 18, 2021
ce39a35
Fixed comments
pavankrish123 May 18, 2021
33c181d
fixed readme
pavankrish123 May 18, 2021
4bd909d
fixed per review comments
pavankrish123 May 18, 2021
23c9b26
removed needless condition
pavankrish123 May 18, 2021
98c258e
fxied tests
pavankrish123 May 18, 2021
7ff009c
fixed lint issues
pavankrish123 May 18, 2021
9ff5660
Fixed module name bearertokenauth -> bearertokenauthextension
pavankrish123 May 19, 2021
b6dff65
fixed import
pavankrish123 May 19, 2021
c24b316
Merge branch 'master' into client_auth_ext
pavankrish123 May 19, 2021
fcc50f3
Fixed tests
pavankrish123 May 19, 2021
40079fd
fixed tests
pavankrish123 May 19, 2021
d8cb3eb
Merge branch 'master' into client_auth_ext
pavankrish123 May 20, 2021
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
27 changes: 20 additions & 7 deletions config/configauth/clientauth.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
// Copyright The OpenTelemetry 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 configauth

import (
"fmt"
"net/http"

"google.golang.org/grpc/credentials"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config"
"google.golang.org/grpc/credentials"
"net/http"
)


// ClientAuth is an Extension that can be used as an authenticator for the configauth.Authentication option.
// Authenticators are then included as part of OpenTelemetry Collector builds and can be referenced by their
// names from the Authentication configuration. .
pavankrish123 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -42,9 +57,8 @@ func GetHTTPClientAuth(extensions map[config.NamedEntity]component.Extension, re
if name.Name() == requested {
if auth, ok := ext.(HTTPClientAuth); ok {
return auth, nil
} else {
return nil, fmt.Errorf("requested authenticator is not for HTTP clients")
}
return nil, fmt.Errorf("requested authenticator is not for HTTP clients")
}
}
return nil, fmt.Errorf("failed to resolve authenticator %q: %w", requested, errAuthenticatorNotFound)
Expand All @@ -62,9 +76,8 @@ func GetGRPCClientAuth(extensions map[config.NamedEntity]component.Extension, re
if name.Name() == requested {
if auth, ok := ext.(GRPCClientAuth); ok {
return auth, nil
} else {
return nil, fmt.Errorf("requested authenticator is not for gRPC clients")
}
return nil, fmt.Errorf("requested authenticator is not for gRPC clients")
}
}
return nil, fmt.Errorf("failed to resolve authenticator %q: %w", requested, errAuthenticatorNotFound)
Expand Down
57 changes: 39 additions & 18 deletions config/confighttp/confighttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ package confighttp

import (
"crypto/tls"
"fmt"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/config/configauth"
"net"
"net/http"
"time"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/config/configauth"

"github.com/rs/cors"

"go.opentelemetry.io/collector/config/configtls"
Expand Down Expand Up @@ -58,8 +58,31 @@ type HTTPClientSettings struct {
Auth *configauth.Authentication `mapstructure:"auth,omitempty"`
}

type toClientOptions struct {
extensionsMap map[config.NamedEntity]component.Extension
}

// ToClientOption is an option to add/change additional configuration on top of HTTPClientSettings
// to construct HTTPClientSettings.ToClient().
type ToClientOption func(options *toClientOptions)

// WithExtensionsConfiguration is passed to HTTPClientSettings.ToClient() in order to
// extend HTTPClientSettings with the configuration provided through extensions
// e.g Authenticator configuration via extensions
func WithExtensionsConfiguration(ext map[config.NamedEntity]component.Extension) ToClientOption {
return func(opts *toClientOptions) {
opts.extensionsMap = ext
}
}

// ToClient creates an HTTP client.
func (hcs *HTTPClientSettings) ToClient() (*http.Client, error) {
func (hcs *HTTPClientSettings) ToClient(opts ...ToClientOption) (*http.Client, error) {
// apply client options
clientOptions := &toClientOptions{}
for _, opt := range opts {
opt(clientOptions)
}

tlsCfg, err := hcs.TLSSetting.LoadTLSConfig()
if err != nil {
return nil, err
Expand All @@ -83,6 +106,17 @@ func (hcs *HTTPClientSettings) ToClient() (*http.Client, error) {
}
}

if clientOptions.extensionsMap != nil && hcs.Auth != nil {
httpCustomAuthRoundTripper, aerr := configauth.GetHTTPClientAuth(clientOptions.extensionsMap, hcs.Auth.AuthenticatorName)
if aerr != nil {
return nil, aerr
}
clientTransport, err = httpCustomAuthRoundTripper.RoundTripper(clientTransport)
if err != nil {
return nil, err
}
}

if hcs.CustomRoundTripper != nil {
clientTransport, err = hcs.CustomRoundTripper(clientTransport)
if err != nil {
Expand All @@ -96,19 +130,6 @@ func (hcs *HTTPClientSettings) ToClient() (*http.Client, error) {
}, nil
}

// AuthRoundTripper intercepts base transport and returns a new authenticated transport.
func (hcs *HTTPClientSettings) AuthRoundTripper(clientBaseTransport http.RoundTripper, ext map[config.NamedEntity]component.Extension) (http.RoundTripper, error) {
if hcs.Auth != nil {
return nil, fmt.Errorf("configuration for auth absent")
}

httpCustomAuthRoundTripper, err := configauth.GetHTTPClientAuth(ext, hcs.Auth.AuthenticatorName)
if err != nil {
return nil, err
}
return httpCustomAuthRoundTripper.RoundTripper(clientBaseTransport)
}

// Custom RoundTripper that add headers
type headerRoundTripper struct {
transport http.RoundTripper
Expand Down
117 changes: 117 additions & 0 deletions config/confighttp/confighttp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package confighttp

import (
"context"
"errors"
"fmt"
"io/ioutil"
Expand All @@ -25,6 +26,10 @@ import (
"testing"
"time"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/config/configauth"

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

Expand Down Expand Up @@ -120,6 +125,118 @@ func TestHTTPClientSettingsError(t *testing.T) {
}
}

type mockHTTPClientAuth struct {
forceError bool
err error
}

func (m *mockHTTPClientAuth) Start(_ context.Context, _ component.Host) error {
return nil
}

func (m *mockHTTPClientAuth) Shutdown(_ context.Context) error {
return nil
}

type customRoundTripper struct {
}

var _ http.RoundTripper = (*customRoundTripper)(nil)

func (c *customRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
return nil, nil
}

func (m *mockHTTPClientAuth) RoundTripper(base http.RoundTripper) (http.RoundTripper, error) {
if m.forceError {
return nil, m.err
}
return &customRoundTripper{}, nil
}

var _ configauth.HTTPClientAuth = (*mockHTTPClientAuth)(nil)

func TestHTTPClientSettingWithAuthConfig(t *testing.T) {
tests := []struct {
name string
shouldErr bool
settings HTTPClientSettings
extensionMap map[config.NamedEntity]component.Extension
}{
{
name: "no_auth_extension_enabled",
settings: HTTPClientSettings{
Endpoint: "localhost:1234",
Auth: nil,
},
shouldErr: false,
extensionMap: map[config.NamedEntity]component.Extension{
&config.ExtensionSettings{
NameVal: "mock",
TypeVal: "mock",
}: &mockHTTPClientAuth{},
},
},
{
name: "with_auth_configuration_has_no_extension",
settings: HTTPClientSettings{
Endpoint: "localhost:1234",
Auth: &configauth.Authentication{AuthenticatorName: "dummy"},
},
shouldErr: true,
extensionMap: map[config.NamedEntity]component.Extension{
&config.ExtensionSettings{
NameVal: "mock",
TypeVal: "mock",
}: &mockHTTPClientAuth{},
},
},
{
name: "with_auth_configuration_has_extension",
settings: HTTPClientSettings{
Endpoint: "localhost:1234",
Auth: &configauth.Authentication{AuthenticatorName: "mock"},
},
shouldErr: false,
extensionMap: map[config.NamedEntity]component.Extension{
&config.ExtensionSettings{
NameVal: "mock",
TypeVal: "mock",
}: &mockHTTPClientAuth{},
},
},
{
name: "with_auth_configuration_has_err_extension",
settings: HTTPClientSettings{
Endpoint: "localhost:1234",
Auth: &configauth.Authentication{AuthenticatorName: "mock"},
},
shouldErr: true,
extensionMap: map[config.NamedEntity]component.Extension{
&config.ExtensionSettings{
NameVal: "mock",
TypeVal: "mock",
}: &mockHTTPClientAuth{forceError: true, err: errors.New("dummy extension")},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
client, err := test.settings.ToClient(WithExtensionsConfiguration(test.extensionMap))
if test.shouldErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.NotNil(t, client)
if test.settings.Auth != nil {
_, ok := client.Transport.(*customRoundTripper)
assert.True(t, ok)
}
})
}
}

func TestHTTPServerSettingsError(t *testing.T) {
tests := []struct {
settings HTTPServerSettings
Expand Down
44 changes: 17 additions & 27 deletions exporter/otlphttpexporter/otlp.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"context"
"errors"
"fmt"
"go.opentelemetry.io/collector/component"
"io"
"io/ioutil"
"net/http"
Expand All @@ -28,16 +27,19 @@ import (
"strings"
"time"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configgrpc"
"go.opentelemetry.io/collector/config/confighttp"
"go.opentelemetry.io/collector/internal/middleware"

pavankrish123 marked this conversation as resolved.
Show resolved Hide resolved
"go.uber.org/zap"
"google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/protobuf/proto"

"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/config/configgrpc"
"go.opentelemetry.io/collector/consumer/consumererror"
"go.opentelemetry.io/collector/consumer/pdata"
"go.opentelemetry.io/collector/exporter/exporterhelper"
"go.opentelemetry.io/collector/internal/middleware"
)

type exporterImp struct {
Expand Down Expand Up @@ -66,41 +68,29 @@ func newExporter(cfg config.Exporter, logger *zap.Logger) (*exporterImp, error)
}
}

client, err := oCfg.HTTPClientSettings.ToClient()
if err != nil {
return nil, err
}

if oCfg.Compression != "" {
if strings.ToLower(oCfg.Compression) == configgrpc.CompressionGzip {
client.Transport = middleware.NewCompressRoundTripper(client.Transport)
} else {
return nil, fmt.Errorf("unsupported compression type %q", oCfg.Compression)
}
}

// client construction is deferred to start
return &exporterImp{
config: oCfg,
client: client,
logger: logger,
}, nil
}

// start overrides defaults base exporters start (no op) to attach auth transport to the http client.
// This is the only place we get hold of Extensions which are required to construct auth round tripper.
// start actually creates the HTTP client. The client construction is deferred till this point as this
// is the only place we get hold of Extensions which are required to construct auth round tripper.
func (e *exporterImp) start(_ context.Context, host component.Host) error {
// nothing to do if auth is not specified
if e.config.Auth == nil {
return nil
client, err := e.config.HTTPClientSettings.ToClient(confighttp.WithExtensionsConfiguration(host.GetExtensions()))
if err != nil {
return err
}

if e.config.HTTPClientSettings.Auth != nil {
transport, err := e.config.HTTPClientSettings.AuthRoundTripper(e.client.Transport, host.GetExtensions())
if err != nil {
return err
if e.config.Compression != "" {
if strings.ToLower(e.config.Compression) == configgrpc.CompressionGzip {
client.Transport = middleware.NewCompressRoundTripper(client.Transport)
} else {
return fmt.Errorf("unsupported compression type %q", e.config.Compression)
}
e.client.Transport = transport
}
e.client = client
return nil
}

Expand Down
Loading