Skip to content
Closed
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
70 changes: 64 additions & 6 deletions extension/beatsauthextension/authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ package beatsauthextension // import "github.com/elastic/opentelemetry-collector

import (
"context"
"errors"
"fmt"
"net/http"
"time"

"github.com/elastic/beats/v7/libbeat/common/transport/kerberos"
"github.com/elastic/elastic-agent-libs/config"
"github.com/elastic/elastic-agent-libs/logp"
"github.com/elastic/elastic-agent-libs/transport/httpcommon"
krbclient "github.com/jcmturner/gokrb5/v8/client"
krbconfig "github.com/jcmturner/gokrb5/v8/config"
"github.com/jcmturner/gokrb5/v8/keytab"
"github.com/jcmturner/gokrb5/v8/spnego"
"go.elastic.co/apm/module/apmelasticsearch/v2"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/component/componentstatus"
Expand All @@ -38,6 +44,10 @@ var _ extensionauth.HTTPClient = (*authenticator)(nil)
var _ extensionauth.GRPCClient = (*authenticator)(nil)
var _ extension.Extension = (*authenticator)(nil)

var (
ErrInvalidAuthType = errors.New("invalid authentication type")
)

// roundTripperProvider is an interface that provides a RoundTripper
type roundTripperProvider interface {
RoundTripper() http.RoundTripper
Expand Down Expand Up @@ -74,7 +84,7 @@ func (a *authenticator) Start(_ context.Context, host component.Host) error {
}

var provider roundTripperProvider
client, err := getHttpClient(a)
prov, err := getHttpClient(a)
if err != nil {
componentstatus.ReportStatus(host, componentstatus.NewPermanentErrorEvent(err))
err = fmt.Errorf("failed creating http client: %w", err)
Expand All @@ -85,7 +95,7 @@ func (a *authenticator) Start(_ context.Context, host component.Host) error {
provider = &errorRoundTripperProvider{err: err}
} else {
componentstatus.ReportStatus(host, componentstatus.NewEvent(componentstatus.StatusOK))
provider = &httpClientProvider{client: client}
provider = prov
}

a.rtProvider = provider
Expand Down Expand Up @@ -122,24 +132,28 @@ func (a *authenticator) PerRPCCredentials() (credentials.PerRPCCredentials, erro
return nil, nil
}

func getHttpClient(a *authenticator) (*http.Client, error) {
func getHttpClient(a *authenticator) (roundTripperProvider, error) {
parsedCfg, err := config.NewConfigFrom(a.cfg.BeatAuthConfig)
if err != nil {
return nil, fmt.Errorf("failed creating config: %w", err)
}

beatAuthConfig := httpcommon.HTTPTransportSettings{}
beatAuthConfig := esAuthConfig{}
err = parsedCfg.Unpack(&beatAuthConfig)
if err != nil {
return nil, fmt.Errorf("failed unpacking config: %w", err)
}

client, err := beatAuthConfig.Client(a.getHTTPOptions(beatAuthConfig.IdleConnTimeout)...)
client, err := beatAuthConfig.Transport.Client(a.getHTTPOptions(beatAuthConfig.Transport.IdleConnTimeout)...)
if err != nil {
return nil, fmt.Errorf("failed creating http client: %w", err)
}

return client, nil
if beatAuthConfig.Kerberos.IsEnabled() {
return NewKerberosClientProvider(beatAuthConfig.Kerberos, client)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return NewKerberosClientProvider(beatAuthConfig.Kerberos, client)
p, err := NewKerberosClientProvider(beatAuthConfig.Kerberos, client)
if err != nil {
return nil, fmt.Errorf("error creating Kerberos client provider: %w", err)
}
return p, nil

Let's wrap the error, otherwise it will be difficult to understand the "invalid authentication type" error message.

}

return &httpClientProvider{client: client}, nil
}

// httpClientProvider provides a RoundTripper from an http.Client
Expand All @@ -151,6 +165,50 @@ func (h *httpClientProvider) RoundTripper() http.RoundTripper {
return h.client.Transport
}

// kerberosClientProvider provides a kerberos enabled roundtripper
type kerberosClientProvider struct {
kerberosClient *krbclient.Client
httpClient *http.Client
}

func NewKerberosClientProvider(config *kerberos.Config, httpClient *http.Client) (*kerberosClientProvider, error) {
var krbClient *krbclient.Client
krbConf, err := krbconfig.Load(config.ConfigPath)
if err != nil {
return nil, fmt.Errorf("error creating Kerberos client: %w", err)
}

switch config.AuthType {
// case 1 is password auth
case 1:
krbClient = krbclient.NewWithPassword(config.Username, config.Realm, config.Password, krbConf)
// case 2 is keytab auth
case 2:
kTab, err := keytab.Load(config.KeyTabPath)
if err != nil {
return nil, fmt.Errorf("cannot load keytab file %s: %w", config.KeyTabPath, err)
}
krbClient = krbclient.NewWithKeytab(config.Username, config.Realm, kTab, krbConf)
default:
return nil, ErrInvalidAuthType
}

return &kerberosClientProvider{kerberosClient: krbClient, httpClient: httpClient}, nil
}
func (k *kerberosClientProvider) RoundTripper() http.RoundTripper {
return k
}

func (k *kerberosClientProvider) RoundTrip(req *http.Request) (*http.Response, error) {
// set appropriate headers on request
err := spnego.SetSPNEGOHeader(k.kerberosClient, req, "")
if err != nil {
return nil, err
}

return k.httpClient.Transport.RoundTrip(req)
}

// errorRoundTripperProvider provides a RoundTripper that always returns an error
type errorRoundTripperProvider struct {
err error
Expand Down
7 changes: 7 additions & 0 deletions extension/beatsauthextension/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package beatsauthextension // import "github.com/elastic/opentelemetry-collector-components/extension/beatsauthextension"

import (
"github.com/elastic/beats/v7/libbeat/common/transport/kerberos"
"github.com/elastic/elastic-agent-libs/transport/httpcommon"
"go.opentelemetry.io/collector/component"
)

Expand All @@ -26,6 +28,11 @@ type Config struct {
ContinueOnError bool `mapstructure:"continue_on_error"`
}

type esAuthConfig struct {
Kerberos *kerberos.Config `config:"kerberos"`
Transport httpcommon.HTTPTransportSettings `config:",inline"`
}

func createDefaultConfig() component.Config {
return &Config{}
}
31 changes: 22 additions & 9 deletions extension/beatsauthextension/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ module github.com/elastic/opentelemetry-collector-components/extension/beatsauth
go 1.24.0

require (
github.com/elastic/beats/v7 v7.17.29
Copy link
Contributor Author

@khushijain21 khushijain21 Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only import beats for Kerberos config creating/validation.

There is a PR up to move kerberos package to elastic-agent-libs so that we can do not have to import beats elastic/elastic-agent-libs#360. The CI failure is also related to the same

github.com/elastic/elastic-agent-libs v0.24.1
github.com/jcmturner/gokrb5/v8 v8.4.4
github.com/stretchr/testify v1.11.1
go.elastic.co/apm/module/apmelasticsearch/v2 v2.7.1
go.opentelemetry.io/collector/component v1.44.0
Expand All @@ -22,12 +24,12 @@ require (

require (
github.com/armon/go-radix v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/elastic/go-sysinfo v1.14.0 // indirect
github.com/elastic/go-ucfg v0.8.5 // indirect
github.com/elastic/go-windows v1.0.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/elastic/go-sysinfo v1.15.3 // indirect
github.com/elastic/go-ucfg v0.8.8 // indirect
github.com/elastic/go-windows v1.0.2 // indirect
github.com/elastic/pkcs8 v1.0.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
Expand All @@ -39,22 +41,28 @@ require (
github.com/golang/snappy v1.0.0 // indirect
github.com/google/go-tpm v0.9.6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/knadh/koanf/maps v0.1.2 // indirect
github.com/knadh/koanf/providers/confmap v1.0.0 // indirect
github.com/knadh/koanf/v2 v2.3.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/procfs v0.13.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/rs/cors v1.11.1 // indirect
go.elastic.co/apm/module/apmhttp/v2 v2.7.1 // indirect
go.elastic.co/apm/v2 v2.7.1 // indirect
Expand Down Expand Up @@ -89,6 +97,11 @@ require (
golang.org/x/text v0.28.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect
google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
gopkg.in/jcmturner/gokrb5.v7 v7.5.0 // indirect
gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v1.0.1 // indirect
Expand Down
Loading
Loading