From 4b9b1399774eed286cc3d8202652b861581e818a Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Tue, 1 Oct 2024 17:20:53 +0200 Subject: [PATCH 1/5] feat: add possibility to inject auth info from secrets Signed-off-by: Kristof Gyuracz --- api/telemetry/v1alpha1/otlp_config.go | 9 +- api/telemetry/v1alpha1/output_types.go | 25 ++- .../v1alpha1/zz_generated.deepcopy.go | 98 ++++++++- .../telemetry.kube-logging.dev_outputs.yaml | 59 ++++- .../telemetry.kube-logging.dev_outputs.yaml | 59 ++++- go.mod | 53 +++-- go.sum | 100 +++++---- .../telemetry/collector_controller.go | 34 ++- .../otel_col_conf_test_fixtures/complex.yaml | 5 + .../controller/telemetry/otel_conf_gen.go | 208 ++++++++++++++---- .../telemetry/otel_conf_gen_test.go | 115 ++++++---- 11 files changed, 593 insertions(+), 172 deletions(-) diff --git a/api/telemetry/v1alpha1/otlp_config.go b/api/telemetry/v1alpha1/otlp_config.go index df0d9aec..6f70f039 100644 --- a/api/telemetry/v1alpha1/otlp_config.go +++ b/api/telemetry/v1alpha1/otlp_config.go @@ -110,7 +110,7 @@ type GRPCClientConfig struct { Authority string `json:"authority,omitempty" yaml:"authority,omitempty"` // Auth configuration for outgoing RPCs. - Auth string `json:"auth,omitempty" yaml:"auth,omitempty"` //TODO this is a reference *configauth.Authentication + Auth *Authentication `json:"auth,omitempty" yaml:"auth,omitempty"` } // TLSClientSetting contains TLS configurations that are specific to client @@ -174,6 +174,11 @@ type TLSSetting struct { ReloadInterval time.Duration `json:"reload_interval,omitempty" yaml:"reload_interval,omitempty"` } +type Authentication struct { + // AuthenticatorID specifies the name of the extension to use in order to authenticate the incoming data point. + AuthenticatorID string `json:"authenticator,omitempty"` +} + // ClientConfig defines settings for creating an HTTP client. type HTTPClientConfig struct { // The target URL to send data to (e.g.: http://some.url:9411/v1/traces). @@ -200,7 +205,7 @@ type HTTPClientConfig struct { Headers map[string]configopaque.String `json:"headers,omitempty" yaml:"headers,omitempty"` // Auth configuration for outgoing HTTP calls. - Auth string `json:"auth,omitempty" yaml:"auth,omitempty"` //TODO this is a reference *configauth.Authentication + Auth Authentication `json:"auth,omitempty" yaml:"auth,omitempty"` // The compression key for supported compression types within collector. Compression configcompression.Type `json:"compression,omitempty" yaml:"compression,omitempty"` diff --git a/api/telemetry/v1alpha1/output_types.go b/api/telemetry/v1alpha1/output_types.go index ccee2f74..aca62b48 100644 --- a/api/telemetry/v1alpha1/output_types.go +++ b/api/telemetry/v1alpha1/output_types.go @@ -17,6 +17,8 @@ package v1alpha1 import ( "time" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -28,9 +30,26 @@ type OutputSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - OTLPGRPC *OTLPGRPC `json:"otlp,omitempty"` - Fluentforward *Fluentforward `json:"fluentforward,omitempty"` - OTLPHTTP *OTLPHTTP `json:"otlphttp,omitempty"` + OTLPGRPC *OTLPGRPC `json:"otlp,omitempty"` + Fluentforward *Fluentforward `json:"fluentforward,omitempty"` + OTLPHTTP *OTLPHTTP `json:"otlphttp,omitempty"` + Authentication *OutputAuth `json:"authentication,omitempty"` +} + +type OutputAuth struct { + BasicAuth *BasicAuthConfig `json:"basicauth,omitempty"` + BearerAuth *BearerAuthConfig `json:"bearerauth,omitempty"` +} + +type BasicAuthConfig struct { + SecretRef *corev1.SecretReference `json:"secretRef,omitempty"` + UsernameField string `json:"usernameField,omitempty"` + PasswordField string `json:"passwordField,omitempty"` +} + +type BearerAuthConfig struct { + SecretRef *corev1.SecretReference `json:"secretRef,omitempty"` + TokenField string `json:"tokenField,omitempty"` } // OTLP grpc exporter config ref: https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/otlpexporter/config.go diff --git a/api/telemetry/v1alpha1/zz_generated.deepcopy.go b/api/telemetry/v1alpha1/zz_generated.deepcopy.go index b8e223c1..baa7a051 100644 --- a/api/telemetry/v1alpha1/zz_generated.deepcopy.go +++ b/api/telemetry/v1alpha1/zz_generated.deepcopy.go @@ -21,11 +21,27 @@ package v1alpha1 import ( "github.com/cisco-open/operator-tools/pkg/typeoverride" "go.opentelemetry.io/collector/config/configopaque" - "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" timex "time" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Authentication) DeepCopyInto(out *Authentication) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Authentication. +func (in *Authentication) DeepCopy() *Authentication { + if in == nil { + return nil + } + out := new(Authentication) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *BackOffConfig) DeepCopyInto(out *BackOffConfig) { *out = *in @@ -41,6 +57,46 @@ func (in *BackOffConfig) DeepCopy() *BackOffConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BasicAuthConfig) DeepCopyInto(out *BasicAuthConfig) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(v1.SecretReference) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BasicAuthConfig. +func (in *BasicAuthConfig) DeepCopy() *BasicAuthConfig { + if in == nil { + return nil + } + out := new(BasicAuthConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BearerAuthConfig) DeepCopyInto(out *BearerAuthConfig) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(v1.SecretReference) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BearerAuthConfig. +func (in *BearerAuthConfig) DeepCopy() *BearerAuthConfig { + if in == nil { + return nil + } + out := new(BearerAuthConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Collector) DeepCopyInto(out *Collector) { *out = *in @@ -192,6 +248,11 @@ func (in *GRPCClientConfig) DeepCopyInto(out *GRPCClientConfig) { (*out)[key] = val } } + if in.Auth != nil { + in, out := &in.Auth, &out.Auth + *out = new(Authentication) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GRPCClientConfig. @@ -215,6 +276,7 @@ func (in *HTTPClientConfig) DeepCopyInto(out *HTTPClientConfig) { (*out)[key] = val } } + out.Auth = in.Auth if in.MaxIdleConns != nil { in, out := &in.MaxIdleConns, &out.MaxIdleConns *out = new(int) @@ -371,6 +433,31 @@ func (in *Output) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OutputAuth) DeepCopyInto(out *OutputAuth) { + *out = *in + if in.BasicAuth != nil { + in, out := &in.BasicAuth, &out.BasicAuth + *out = new(BasicAuthConfig) + (*in).DeepCopyInto(*out) + } + if in.BearerAuth != nil { + in, out := &in.BearerAuth, &out.BearerAuth + *out = new(BearerAuthConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OutputAuth. +func (in *OutputAuth) DeepCopy() *OutputAuth { + if in == nil { + return nil + } + out := new(OutputAuth) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OutputList) DeepCopyInto(out *OutputList) { *out = *in @@ -421,6 +508,11 @@ func (in *OutputSpec) DeepCopyInto(out *OutputSpec) { *out = new(OTLPHTTP) (*in).DeepCopyInto(*out) } + if in.Authentication != nil { + in, out := &in.Authentication, &out.Authentication + *out = new(OutputAuth) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OutputSpec. @@ -673,14 +765,14 @@ func (in *TenantSpec) DeepCopyInto(out *TenantSpec) { *out = *in if in.SubscriptionNamespaceSelectors != nil { in, out := &in.SubscriptionNamespaceSelectors, &out.SubscriptionNamespaceSelectors - *out = make([]v1.LabelSelector, len(*in)) + *out = make([]metav1.LabelSelector, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.LogSourceNamespaceSelectors != nil { in, out := &in.LogSourceNamespaceSelectors, &out.LogSourceNamespaceSelectors - *out = make([]v1.LabelSelector, len(*in)) + *out = make([]metav1.LabelSelector, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } diff --git a/charts/telemetry-controller/crds/telemetry.kube-logging.dev_outputs.yaml b/charts/telemetry-controller/crds/telemetry.kube-logging.dev_outputs.yaml index 0c305057..73b18a30 100644 --- a/charts/telemetry-controller/crds/telemetry.kube-logging.dev_outputs.yaml +++ b/charts/telemetry-controller/crds/telemetry.kube-logging.dev_outputs.yaml @@ -41,6 +41,51 @@ spec: spec: description: OutputSpec defines the desired state of Output properties: + authentication: + properties: + basicauth: + properties: + passwordField: + type: string + secretRef: + description: |- + SecretReference represents a Secret Reference. It has enough information to retrieve secret + in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which + the secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + usernameField: + type: string + type: object + bearerauth: + properties: + secretRef: + description: |- + SecretReference represents a Secret Reference. It has enough information to retrieve secret + in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which + the secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + tokenField: + type: string + type: object + type: object fluentforward: properties: compress_gzip: @@ -207,7 +252,12 @@ spec: properties: auth: description: Auth configuration for outgoing RPCs. - type: string + properties: + authenticator: + description: AuthenticatorID specifies the name of the extension + to use in order to authenticate the incoming data point. + type: string + type: object authority: description: |- WithAuthority parameter configures client to rewrite ":authority" header @@ -405,7 +455,12 @@ spec: properties: auth: description: Auth configuration for outgoing HTTP calls. - type: string + properties: + authenticator: + description: AuthenticatorID specifies the name of the extension + to use in order to authenticate the incoming data point. + type: string + type: object compression: description: The compression key for supported compression types within collector. diff --git a/config/crd/bases/telemetry.kube-logging.dev_outputs.yaml b/config/crd/bases/telemetry.kube-logging.dev_outputs.yaml index 0c305057..73b18a30 100644 --- a/config/crd/bases/telemetry.kube-logging.dev_outputs.yaml +++ b/config/crd/bases/telemetry.kube-logging.dev_outputs.yaml @@ -41,6 +41,51 @@ spec: spec: description: OutputSpec defines the desired state of Output properties: + authentication: + properties: + basicauth: + properties: + passwordField: + type: string + secretRef: + description: |- + SecretReference represents a Secret Reference. It has enough information to retrieve secret + in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which + the secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + usernameField: + type: string + type: object + bearerauth: + properties: + secretRef: + description: |- + SecretReference represents a Secret Reference. It has enough information to retrieve secret + in any namespace + properties: + name: + description: name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: namespace defines the space within which + the secret name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic + tokenField: + type: string + type: object + type: object fluentforward: properties: compress_gzip: @@ -207,7 +252,12 @@ spec: properties: auth: description: Auth configuration for outgoing RPCs. - type: string + properties: + authenticator: + description: AuthenticatorID specifies the name of the extension + to use in order to authenticate the incoming data point. + type: string + type: object authority: description: |- WithAuthority parameter configures client to rewrite ":authority" header @@ -405,7 +455,12 @@ spec: properties: auth: description: Auth configuration for outgoing HTTP calls. - type: string + properties: + authenticator: + description: AuthenticatorID specifies the name of the extension + to use in order to authenticate the incoming data point. + type: string + type: object compression: description: The compression key for supported compression types within collector. diff --git a/go.mod b/go.mod index e8eb5ad7..43b99106 100644 --- a/go.mod +++ b/go.mod @@ -18,11 +18,13 @@ require ( ) require ( + github.com/go-viper/mapstructure/v2 v2.1.0 go.opentelemetry.io/collector/config/configauth v0.103.0 - go.opentelemetry.io/collector/config/configopaque v1.7.0 + go.opentelemetry.io/collector/config/configopaque v1.16.0 ) require ( + github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 // indirect github.com/briandowns/spinner v1.23.0 // indirect github.com/cisco-open/k8s-objectmatcher v1.9.0 // indirect github.com/cppforlife/go-patch v0.2.0 // indirect @@ -30,36 +32,32 @@ require ( github.com/fatih/color v1.16.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect - github.com/knadh/koanf/maps v0.1.1 // indirect - github.com/knadh/koanf/providers/confmap v0.1.0 // indirect - github.com/knadh/koanf/v2 v2.1.1 // 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/nxadm/tail v1.4.8 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/spf13/cast v1.6.0 // indirect + github.com/tg123/go-htpasswd v1.2.2 // indirect github.com/wayneashleyberry/terminal-dimensions v1.1.0 // indirect - go.opentelemetry.io/collector/component v0.103.0 // indirect - go.opentelemetry.io/collector/config/configtelemetry v0.103.0 // indirect - go.opentelemetry.io/collector/confmap v0.103.0 // indirect - go.opentelemetry.io/collector/extension v0.103.0 // indirect - go.opentelemetry.io/collector/extension/auth v0.103.0 // indirect - go.opentelemetry.io/collector/featuregate v1.10.0 // indirect - go.opentelemetry.io/collector/pdata v1.10.0 // indirect - go.opentelemetry.io/otel v1.27.0 // indirect + go.opentelemetry.io/collector/client v1.16.0 // indirect + go.opentelemetry.io/collector/component v0.110.0 // indirect + go.opentelemetry.io/collector/config/configtelemetry v0.110.0 // indirect + go.opentelemetry.io/collector/extension v0.110.0 // indirect + go.opentelemetry.io/collector/extension/auth v0.110.0 // indirect + go.opentelemetry.io/collector/internal/globalsignal v0.110.0 // indirect + go.opentelemetry.io/collector/pdata v1.16.0 // indirect + go.opentelemetry.io/collector/pipeline v0.110.0 // indirect + go.opentelemetry.io/otel v1.30.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.49.0 // indirect - go.opentelemetry.io/otel/metric v1.27.0 // indirect - go.opentelemetry.io/otel/sdk v1.27.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect - go.opentelemetry.io/otel/trace v1.27.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/grpc v1.64.0 // indirect + go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/sdk v1.30.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect + go.opentelemetry.io/otel/trace v1.30.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.66.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -88,10 +86,11 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mitchellh/mapstructure v1.5.0 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension v0.110.0 + github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension v0.110.0 github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.19.1 github.com/prometheus/client_model v0.6.1 // indirect @@ -103,11 +102,11 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 - golang.org/x/net v0.26.0 // indirect + golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/term v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.22.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 9f54ab92..1805f1da 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ emperror.dev/errors v0.8.1 h1:UavXZ5cSX/4u9iyvH6aDcuGkVjeexUGJ7Ij7G4VfQT0= emperror.dev/errors v0.8.1/go.mod h1:YcRvLPh626Ubn2xqtoprejnA5nFha+TJ+2vew48kWuE= +github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw= +github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= @@ -46,8 +48,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c= -github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w= +github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -66,8 +68,6 @@ github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQN github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= @@ -97,8 +97,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -116,6 +114,10 @@ github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension v0.110.0 h1:OzdaJriUgOT2iyFG4f9pjQdgruYO2P77fw5Z4tjm5iQ= +github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension v0.110.0/go.mod h1:y7jCFpCEEN6HRyeu6tJQtZZkw6q/ZwBa6JTpm//T9NE= +github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension v0.110.0 h1:QfCtczND32VwLrw80qbLcMIPeCMYdsPX6a/MGek0cbc= +github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension v0.110.0/go.mod h1:l1SQz/z61b8I+EQOOK0ZET8qHyTidBbaFWKEnwtTOB4= github.com/open-telemetry/opentelemetry-operator v0.103.0 h1:L0REMuJSMZjqCw7p7fWMn19XkiIULMr3NnHdPLryMQs= github.com/open-telemetry/opentelemetry-operator v0.103.0/go.mod h1:kf5B7DLm4m88avApWmHhBjn66fQfSABM2cuQfHqAR+Y= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= @@ -147,42 +149,50 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tg123/go-htpasswd v1.2.2 h1:tmNccDsQ+wYsoRfiONzIhDm5OkVHQzN3w4FOBAlN6BY= +github.com/tg123/go-htpasswd v1.2.2/go.mod h1:FcIrK0J+6zptgVwK1JDlqyajW/1B4PtuJ/FLWl7nx8A= github.com/wayneashleyberry/terminal-dimensions v1.1.0 h1:EB7cIzBdsOzAgmhTUtTTQXBByuPheP/Zv1zL2BRPY6g= github.com/wayneashleyberry/terminal-dimensions v1.1.0/go.mod h1:2lc/0eWCObmhRczn2SdGSQtgBooLUzIotkkEGXqghyg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/collector/component v0.103.0 h1:j52YAsp8EmqYUotVUwhovkqFZGuxArEkk65V4TI46NE= -go.opentelemetry.io/collector/component v0.103.0/go.mod h1:jKs19tGtCO8Hr5/YM0F+PoFcl8SVe/p4Ge30R6srkbc= +go.opentelemetry.io/collector/client v1.16.0 h1:3m7HzWR41+4M8r9q7UvEDjMBTFMrik/BdvAuwCs0cV4= +go.opentelemetry.io/collector/client v1.16.0/go.mod h1:N01Alc/CouREl18hmxdaQXGfID7dBZrrbsBar7WHkZ0= +go.opentelemetry.io/collector/component v0.110.0 h1:z7uSY/1dcK+vTY2z3v0XxeCoi2wqgHTow/ds3Gozuz4= +go.opentelemetry.io/collector/component v0.110.0/go.mod h1:W99gZdfGtQ5Zg6Bhrwrcl/uZcCG+2qBnZ1z2JO5WCW0= go.opentelemetry.io/collector/config/configauth v0.103.0 h1:tv2Ilj0X9T8ZsDd4mB8Sl+nXQ8CG8MJVQ1Lo4mmE0Pk= go.opentelemetry.io/collector/config/configauth v0.103.0/go.mod h1:VIo8DpFeyOOCMUVoQsBdq3t2snUiBBECP0UxW1bwz/o= go.opentelemetry.io/collector/config/configcompression v1.7.0 h1:OMsuJd5G1UXB09YCc33qvy9cMUYVkSQGLl6j87445GI= go.opentelemetry.io/collector/config/configcompression v1.7.0/go.mod h1:O0fOPCADyGwGLLIf5lf7N3960NsnIfxsm6dr/mIpL+M= -go.opentelemetry.io/collector/config/configopaque v1.7.0 h1:nZh5Hb1ofq9xP1wHLSt4obM85pRTccSeAjV0NbrJeTc= -go.opentelemetry.io/collector/config/configopaque v1.7.0/go.mod h1:vxoDKYYYUF/arrdQJxmfhlgkcsb0DpdzC9KPFP97uuE= -go.opentelemetry.io/collector/config/configtelemetry v0.103.0 h1:KLbhkFqdw9D31t0IhJ/rnhMRvz/s14eie0fKfm5xWns= -go.opentelemetry.io/collector/config/configtelemetry v0.103.0/go.mod h1:WxWKNVAQJg/Io1nA3xLgn/DWLE/W1QOB2+/Js3ACi40= -go.opentelemetry.io/collector/confmap v0.103.0 h1:qKKZyWzropSKfgtGv12JzADOXNgThqH1Vx6qzblBE24= -go.opentelemetry.io/collector/confmap v0.103.0/go.mod h1:TlOmqe/Km3K6WgxyhEAdCb/V1Yp6eSU76fCoiluEa88= -go.opentelemetry.io/collector/extension v0.103.0 h1:vTsd+GElvT7qKk9Y9d6UKuuT2Ngx0mai8Q48hkKQMwM= -go.opentelemetry.io/collector/extension v0.103.0/go.mod h1:rp2l3xskNKWv0yBCyU69Pv34TnP1QVD1ijr0zSndnsM= -go.opentelemetry.io/collector/extension/auth v0.103.0 h1:i7cQl+Ewpve/DIN4rFMg1GiyUPE14LZsYWrJ1RqtP84= -go.opentelemetry.io/collector/extension/auth v0.103.0/go.mod h1:JdYBS/EkPAz2APAi8g7xTiSRlZTc7c4H82AQM9epzxw= -go.opentelemetry.io/collector/featuregate v1.10.0 h1:krSqokHTp7JthgmtewysqHuOAkcuuZl7G2n91s7HygE= -go.opentelemetry.io/collector/featuregate v1.10.0/go.mod h1:PsOINaGgTiFc+Tzu2K/X2jP+Ngmlp7YKGV1XrnBkH7U= -go.opentelemetry.io/collector/pdata v1.10.0 h1:oLyPLGvPTQrcRT64ZVruwvmH/u3SHTfNo01pteS4WOE= -go.opentelemetry.io/collector/pdata v1.10.0/go.mod h1:IHxHsp+Jq/xfjORQMDJjSH6jvedOSTOyu3nbxqhWSYE= -go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= -go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/collector/config/configopaque v1.16.0 h1:83cVlPL151kHWrHLUAkdfwvnhp68x0XPxEkSBSfEapE= +go.opentelemetry.io/collector/config/configopaque v1.16.0/go.mod h1:6zlLIyOoRpJJ+0bEKrlZOZon3rOp5Jrz9fMdR4twOS4= +go.opentelemetry.io/collector/config/configtelemetry v0.110.0 h1:V8Y/Xv7TJpnNGHLrheRKrMydcKBxWYAZ+dj71Kllyos= +go.opentelemetry.io/collector/config/configtelemetry v0.110.0/go.mod h1:R0MBUxjSMVMIhljuDHWIygzzJWQyZHXXWIgQNxcFwhc= +go.opentelemetry.io/collector/confmap v1.16.0 h1:0bWw/XSosX6xoE1sGsaD3glzRtSxanrF4sgib3jAYr4= +go.opentelemetry.io/collector/confmap v1.16.0/go.mod h1:GrIZ12P/9DPOuTpe2PIS51a0P/ZM6iKtByVee1Uf3+k= +go.opentelemetry.io/collector/consumer v0.110.0 h1:CnB83KSFQxhFAbNJwTM0blahg16xa6CyUnIIA5qPMbA= +go.opentelemetry.io/collector/consumer v0.110.0/go.mod h1:WlzhfwDfwKkEa5XFdN5x9+jjp9ZF5EUSmtOgVe69zm0= +go.opentelemetry.io/collector/extension v0.110.0 h1:AYFk57W25f7xOo3I6pV0rWNWVtOLZsW+lzFCctnvCkU= +go.opentelemetry.io/collector/extension v0.110.0/go.mod h1:zD/pw9o83SFyn/DCbBdBcH0eUPyGtYgpMSAOqotFYRc= +go.opentelemetry.io/collector/extension/auth v0.110.0 h1:9SHC2sF/KR99LciHABDXRIsXLiujzIjTJpWHO0V8Bqg= +go.opentelemetry.io/collector/extension/auth v0.110.0/go.mod h1:NjpHds6mjeT8Zn2KJVxZtV9c59AoIr6RlBha1RpmScQ= +go.opentelemetry.io/collector/internal/globalsignal v0.110.0 h1:S6bfFEiek8vJeXAbciWS7W8UR6ZrVJB3ftNyFTMHQaY= +go.opentelemetry.io/collector/internal/globalsignal v0.110.0/go.mod h1:GqMXodPWOxK5uqpX8MaMXC2389y2XJTa5nPwf8FYDK8= +go.opentelemetry.io/collector/pdata v1.16.0 h1:g02K8jlRnmQ7TQDuXpdgVL6vIxIVqr5Gbb1qIR27rto= +go.opentelemetry.io/collector/pdata v1.16.0/go.mod h1:YZZJIt2ehxosYf/Y1pbvexjNWsIGNNrzzlCTO9jC1F4= +go.opentelemetry.io/collector/pipeline v0.110.0 h1:nArQj8lt2R6ajbbmZ0f7JqkzAzvIOSwxsxDEv9HGKHw= +go.opentelemetry.io/collector/pipeline v0.110.0/go.mod h1:qWk90kohDYBgI/1Kw4DQaQU82+y9GJY8MDse7H2JTWg= +go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/exporters/prometheus v0.49.0 h1:Er5I1g/YhfYv9Affk9nJLfH/+qCCVVg1f2R9AbJfqDQ= go.opentelemetry.io/otel/exporters/prometheus v0.49.0/go.mod h1:KfQ1wpjf3zsHjzP149P4LyAwWRupc6c7t1ZJ9eXpKQM= -go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= -go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= -go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= -go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= -go.opentelemetry.io/otel/sdk/metric v1.27.0 h1:5uGNOlpXi+Hbo/DRoI31BSb1v+OGcpv2NemcCrOL8gI= -go.opentelemetry.io/otel/sdk/metric v1.27.0/go.mod h1:we7jJVrYN2kh3mVBlswtPU22K0SA+769l93J6bsyvqw= -go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= -go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= +go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= +go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= +go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= +go.opentelemetry.io/otel/sdk/metric v1.30.0 h1:QJLT8Pe11jyHBHfSAgYH7kEmT24eX792jZO1bo4BXkM= +go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y= +go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -194,6 +204,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -202,8 +214,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -215,14 +227,14 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -237,10 +249,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 4cd33547..fad0830c 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -55,6 +55,11 @@ type TenantFailedError struct { msg string } +type BasicAuthClientAuthConfig struct { + Username string + Password string +} + func (e *TenantFailedError) Error() string { return e.msg } func (r *CollectorReconciler) buildConfigInputForCollector(ctx context.Context, collector *v1alpha1.Collector) (OtelColConfigInput, error) { @@ -64,7 +69,7 @@ func (r *CollectorReconciler) buildConfigInputForCollector(ctx context.Context, tenants, err := r.getTenantsMatchingSelectors(ctx, collector.Spec.TenantSelector) subscriptions := make(map[v1alpha1.NamespacedName]v1alpha1.Subscription) - outputs := []v1alpha1.Output{} + outputs := []OutputWithSecretData{} if err != nil { logger.Error(errors.WithStack(err), "failed listing tenants") @@ -96,19 +101,40 @@ func (r *CollectorReconciler) buildConfigInputForCollector(ctx context.Context, subscriptionOutputMap[subscription.NamespacedName()] = outputNames for _, outputName := range outputNames { + outputWithSecretData := OutputWithSecretData{} + queriedOutput := &v1alpha1.Output{} if err = r.Client.Get(ctx, types.NamespacedName(outputName), queriedOutput); err != nil { logger.Error(errors.WithStack(err), "failed getting outputs for subscription", "subscription", subscription.NamespacedName().String()) return OtelColConfigInput{}, err } - outputs = append(outputs, *queriedOutput) + outputWithSecretData.Output = *queriedOutput + + if queriedOutput.Spec.Authentication != nil { + if queriedOutput.Spec.Authentication.BasicAuth != nil && queriedOutput.Spec.Authentication.BasicAuth.SecretRef != nil { + queriedSecret := &corev1.Secret{} + if err = r.Client.Get(ctx, types.NamespacedName{Namespace: queriedOutput.Spec.Authentication.BasicAuth.SecretRef.Namespace, Name: queriedOutput.Spec.Authentication.BasicAuth.SecretRef.Name}, queriedSecret); err != nil { + logger.Error(errors.WithStack(err), "failed getting secrets for output", "output", queriedOutput.NamespacedName().String()) + } + outputWithSecretData.Secret = *queriedSecret + } + if queriedOutput.Spec.Authentication.BearerAuth != nil && queriedOutput.Spec.Authentication.BearerAuth.SecretRef != nil { + queriedSecret := &corev1.Secret{} + if err = r.Client.Get(ctx, types.NamespacedName{Namespace: queriedOutput.Spec.Authentication.BearerAuth.SecretRef.Namespace, Name: queriedOutput.Spec.Authentication.BearerAuth.SecretRef.Name}, queriedSecret); err != nil { + logger.Error(errors.WithStack(err), "failed getting secrets for output", "output", queriedOutput.NamespacedName().String()) + } + outputWithSecretData.Secret = *queriedSecret + } + } + + outputs = append(outputs, outputWithSecretData) } } otelConfigInput := OtelColConfigInput{ Tenants: tenants, Subscriptions: subscriptions, - Outputs: outputs, + OutputsWithSecretData: outputs, TenantSubscriptionMap: tenantSubscriptionMap, SubscriptionOutputMap: subscriptionOutputMap, Debug: collector.Spec.Debug, @@ -166,7 +192,7 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( Config: otelConfig, Mode: otelv1beta1.ModeDaemonSet, OpenTelemetryCommonFields: otelv1beta1.OpenTelemetryCommonFields{ - Image: "ghcr.io/axoflow/axoflow-otel-collector/axoflow-otel-collector:0.104.0-1", + Image: "ghcr.io/axoflow/axoflow-otel-collector/axoflow-otel-collector:0.104.0-2", ServiceAccount: saName.Name, VolumeMounts: []corev1.VolumeMount{ { diff --git a/internal/controller/telemetry/otel_col_conf_test_fixtures/complex.yaml b/internal/controller/telemetry/otel_col_conf_test_fixtures/complex.yaml index 1152aa02..b13610b9 100644 --- a/internal/controller/telemetry/otel_col_conf_test_fixtures/complex.yaml +++ b/internal/controller/telemetry/otel_col_conf_test_fixtures/complex.yaml @@ -58,6 +58,9 @@ connectors: - logs/tenant_example-tenant-b_subscription_example-tenant-b-ns_subscription-example-3 statement: route() exporters: {} +extensions: + bearertokenauth/collector_otlp-test-output: + token: testtoken processors: attributes/exporter_name_fluentforward-test-output: actions: @@ -149,6 +152,8 @@ processors: spike_limit_percentage: 25 receivers: {} service: + extensions: + - bearertokenauth/collector_otlp-test-output pipelines: logs/output_example-tenant-a-ns_subscription-example-1_collector_loki-test-output: exporters: diff --git a/internal/controller/telemetry/otel_conf_gen.go b/internal/controller/telemetry/otel_conf_gen.go index c893fa64..bf6d7fe9 100644 --- a/internal/controller/telemetry/otel_conf_gen.go +++ b/internal/controller/telemetry/otel_conf_gen.go @@ -22,24 +22,30 @@ import ( "strings" "time" + otelv1beta1 "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" + "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/configopaque" "golang.org/x/exp/maps" + corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/yaml" - otelv1beta1 "github.com/open-telemetry/opentelemetry-operator/apis/v1beta1" - "github.com/prometheus/client_golang/prometheus" - "github.com/kube-logging/telemetry-controller/api/telemetry/v1alpha1" ) +const ( + defaultBasicAuthUsernameField = "username" + defaultBasicAuthPasswordField = "password" + defaultBearerAuthTokenField = "token" +) + type OtelColConfigInput struct { // These must only include resources that are selected by the collector, tenant labelselectors, and listed outputs in the subscriptions - Tenants []v1alpha1.Tenant - Subscriptions map[v1alpha1.NamespacedName]v1alpha1.Subscription - Outputs []v1alpha1.Output - MemoryLimiter v1alpha1.MemoryLimiter + Tenants []v1alpha1.Tenant + Subscriptions map[v1alpha1.NamespacedName]v1alpha1.Subscription + OutputsWithSecretData []OutputWithSecretData + MemoryLimiter v1alpha1.MemoryLimiter // Subscriptions map, where the key is the Tenants' name, value is a slice of subscriptions' namespaced name TenantSubscriptionMap map[string][]v1alpha1.NamespacedName @@ -47,6 +53,11 @@ type OtelColConfigInput struct { Debug bool } +type OutputWithSecretData struct { + Output v1alpha1.Output + Secret corev1.Secret +} + type RoutingConnectorTableItem struct { Statement string `json:"statement"` Pipelines []string `json:"pipelines"` @@ -259,16 +270,26 @@ func (cfgInput *OtelColConfigInput) generateOTLPGRPCExporters(ctx context.Contex logger := log.FromContext(ctx) result := make(map[string]any) - for _, output := range cfgInput.Outputs { - if output.Spec.OTLPGRPC != nil { - name := GetExporterNameForOutput(output) - otlpGrpcValuesMarshaled, err := yaml.Marshal(output.Spec.OTLPGRPC) + for _, output := range cfgInput.OutputsWithSecretData { + if output.Output.Spec.OTLPGRPC != nil { + name := GetExporterNameForOutput(output.Output) + + if output.Output.Spec.Authentication != nil { + if output.Output.Spec.Authentication.BasicAuth != nil { + output.Output.Spec.OTLPGRPC.Auth = &v1alpha1.Authentication{ + AuthenticatorID: fmt.Sprintf("basicauth/%s_%s", output.Output.Namespace, output.Output.Name)} + } else if output.Output.Spec.Authentication.BearerAuth != nil { + output.Output.Spec.OTLPGRPC.Auth = &v1alpha1.Authentication{ + AuthenticatorID: fmt.Sprintf("bearertokenauth/%s_%s", output.Output.Namespace, output.Output.Name)} + } + } + otlpGrpcValuesMarshaled, err := yaml.Marshal(output.Output.Spec.OTLPGRPC) if err != nil { - logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.NamespacedName().String()) + logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.Output.NamespacedName().String()) } var otlpGrpcValues map[string]any if err := yaml.Unmarshal(otlpGrpcValuesMarshaled, &otlpGrpcValues); err != nil { - logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.NamespacedName().String()) + logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.Output.NamespacedName().String()) } result[name] = otlpGrpcValues @@ -282,16 +303,24 @@ func (cfgInput *OtelColConfigInput) generateOTLPHTTPExporters(ctx context.Contex logger := log.FromContext(ctx) result := make(map[string]any) - for _, output := range cfgInput.Outputs { - if output.Spec.OTLPHTTP != nil { - name := GetExporterNameForOutput(output) - otlpHttpValuesMarshaled, err := yaml.Marshal(output.Spec.OTLPHTTP) + for _, output := range cfgInput.OutputsWithSecretData { + if output.Output.Spec.OTLPHTTP != nil { + name := GetExporterNameForOutput(output.Output) + + if output.Output.Spec.Authentication != nil { + if output.Output.Spec.Authentication.BasicAuth != nil { + output.Output.Spec.OTLPHTTP.Auth.AuthenticatorID = fmt.Sprintf("basicauth/%s_%s", output.Output.Namespace, output.Output.Name) + } else if output.Output.Spec.Authentication.BearerAuth != nil { + output.Output.Spec.OTLPHTTP.Auth.AuthenticatorID = fmt.Sprintf("bearertokenauth/%s_%s", output.Output.Namespace, output.Output.Name) + } + } + otlpHttpValuesMarshaled, err := yaml.Marshal(output.Output.Spec.OTLPHTTP) if err != nil { - logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.NamespacedName().String()) + logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.Output.NamespacedName().String()) } var otlpHttpValues map[string]any if err := yaml.Unmarshal(otlpHttpValuesMarshaled, &otlpHttpValues); err != nil { - logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.NamespacedName().String()) + logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.Output.NamespacedName().String()) } result[name] = otlpHttpValues @@ -306,17 +335,17 @@ func (cfgInput *OtelColConfigInput) generateFluentforwardExporters(ctx context.C result := make(map[string]any) - for _, output := range cfgInput.Outputs { - if output.Spec.Fluentforward != nil { + for _, output := range cfgInput.OutputsWithSecretData { + if output.Output.Spec.Fluentforward != nil { // TODO: add proper error handling - name := fmt.Sprintf("fluentforwardexporter/%s_%s", output.Namespace, output.Name) - fluentForwardMarshaled, err := yaml.Marshal(output.Spec.Fluentforward) + name := fmt.Sprintf("fluentforwardexporter/%s_%s", output.Output.Namespace, output.Output.Name) + fluentForwardMarshaled, err := yaml.Marshal(output.Output.Spec.Fluentforward) if err != nil { - logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.NamespacedName().String()) + logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.Output.NamespacedName().String()) } var fluetForwardValues map[string]any if err := yaml.Unmarshal(fluentForwardMarshaled, &fluetForwardValues); err != nil { - logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.NamespacedName().String()) + logger.Error(errors.New("failed to compile config for output"), "failed to compile config for output %q", output.Output.NamespacedName().String()) } result[name] = fluetForwardValues @@ -534,8 +563,8 @@ func (cfgInput *OtelColConfigInput) generateProcessors() map[string]any { processors[fmt.Sprintf("attributes/subscription_%s", subscription.Name)] = generateSubscriptionAttributeProcessor(subscription) } - for _, output := range cfgInput.Outputs { - processors[fmt.Sprintf("attributes/exporter_name_%s", output.Name)] = generateOutputExporterNameProcessor(output) + for _, output := range cfgInput.OutputsWithSecretData { + processors[fmt.Sprintf("attributes/exporter_name_%s", output.Output.Name)] = generateOutputExporterNameProcessor(output.Output) } return processors @@ -652,27 +681,27 @@ func (cfgInput *OtelColConfigInput) generateNamedPipelines() map[string]*otelv1b for _, outputRef := range cfgInput.SubscriptionOutputMap[subscription] { outputPipelineName := fmt.Sprintf("logs/output_%s_%s_%s_%s", subscription.Namespace, subscription.Name, outputRef.Namespace, outputRef.Name) - idx := slices.IndexFunc(cfgInput.Outputs, func(elem v1alpha1.Output) bool { - return outputRef == elem.NamespacedName() + idx := slices.IndexFunc(cfgInput.OutputsWithSecretData, func(elem OutputWithSecretData) bool { + return outputRef == elem.Output.NamespacedName() }) if idx != -1 { - output := cfgInput.Outputs[idx] + output := cfgInput.OutputsWithSecretData[idx] receivers := []string{fmt.Sprintf("routing/subscription_%s_%s_outputs", subscription.Namespace, subscription.Name)} - processors := []string{fmt.Sprintf("attributes/exporter_name_%s", output.Name)} + processors := []string{fmt.Sprintf("attributes/exporter_name_%s", output.Output.Name)} var exporters []string - if output.Spec.OTLPGRPC != nil { - exporters = []string{GetExporterNameForOutput(output), outputCountConnectorName} + if output.Output.Spec.OTLPGRPC != nil { + exporters = []string{GetExporterNameForOutput(output.Output), outputCountConnectorName} } - if output.Spec.OTLPHTTP != nil { - exporters = []string{GetExporterNameForOutput(output), outputCountConnectorName} + if output.Output.Spec.OTLPHTTP != nil { + exporters = []string{GetExporterNameForOutput(output.Output), outputCountConnectorName} } - if output.Spec.Fluentforward != nil { - exporters = []string{GetExporterNameForOutput(output), outputCountConnectorName} + if output.Output.Spec.Fluentforward != nil { + exporters = []string{GetExporterNameForOutput(output.Output), outputCountConnectorName} } if cfgInput.Debug { exporters = append(exporters, "logging/debug") @@ -862,11 +891,87 @@ func (cfgInput *OtelColConfigInput) generateDefaultKubernetesReceiver(namespaces return k8sReceiver } -func (cfgInput *OtelColConfigInput) AssembleConfig(ctx context.Context) otelv1beta1.Config { - exporters := cfgInput.generateExporters(ctx) +type BasicAuthExtensionConfig struct { + ClientAuth BasicClientAuthConfig `json:"client_auth,omitempty"` +} - processors := cfgInput.generateProcessors() +type BasicClientAuthConfig struct { + // Username holds the username to use for client authentication. + Username string `json:"username"` + // Password holds the password to use for client authentication. + Password string `json:"password"` +} + +func generateBasicAuthExtensionsForOutput(output OutputWithSecretData) BasicAuthExtensionConfig { + var effectiveUsernameField, effectivePasswordField string + + if output.Output.Spec.Authentication.BasicAuth.UsernameField != "" { + effectiveUsernameField = output.Output.Spec.Authentication.BasicAuth.UsernameField + } else { + effectiveUsernameField = defaultBasicAuthUsernameField + } + + if output.Output.Spec.Authentication.BasicAuth.PasswordField != "" { + effectivePasswordField = output.Output.Spec.Authentication.BasicAuth.PasswordField + } else { + effectivePasswordField = defaultBasicAuthPasswordField + } + + config := BasicAuthExtensionConfig{} + + if u, ok := output.Secret.Data[effectiveUsernameField]; ok { + config.ClientAuth.Username = string(u) + } + + if p, ok := output.Secret.Data[effectivePasswordField]; ok { + config.ClientAuth.Password = string(p) + } + + return config +} + +type BearerTokenAuthExtensionConfig struct { + BearerToken string `json:"token,omitempty"` +} + +func generateBearerAuthExtensionsForOutput(output OutputWithSecretData) BearerTokenAuthExtensionConfig { + var effectiveTokenField string + + if output.Output.Spec.Authentication.BearerAuth.TokenField != "" { + effectiveTokenField = output.Output.Spec.Authentication.BasicAuth.UsernameField + } else { + effectiveTokenField = defaultBearerAuthTokenField + } + + config := BearerTokenAuthExtensionConfig{} + + if t, ok := output.Secret.Data[effectiveTokenField]; ok { + config.BearerToken = string(t) + } + + return config +} + +func (cfgInput *OtelColConfigInput) generateExtensions() map[string]any { + extensions := make(map[string]any) + + for _, output := range cfgInput.OutputsWithSecretData { + if output.Output.Spec.Authentication != nil { + if output.Output.Spec.Authentication.BasicAuth != nil { + extName := fmt.Sprintf("basicauth/%s_%s", output.Output.Namespace, output.Output.Name) + extensions[extName] = generateBasicAuthExtensionsForOutput(output) + } + if output.Output.Spec.Authentication.BearerAuth != nil { + extName := fmt.Sprintf("bearertokenauth/%s_%s", output.Output.Namespace, output.Output.Name) + extensions[extName] = generateBearerAuthExtensionsForOutput(output) + } + } + } + + return extensions +} +func (cfgInput *OtelColConfigInput) generateReceivers() map[string]any { receivers := make(map[string]any) for tenantName := range cfgInput.TenantSubscriptionMap { @@ -879,6 +984,18 @@ func (cfgInput *OtelColConfigInput) AssembleConfig(ctx context.Context) otelv1be } } + return receivers +} + +func (cfgInput *OtelColConfigInput) AssembleConfig(ctx context.Context) otelv1beta1.Config { + exporters := cfgInput.generateExporters(ctx) + + processors := cfgInput.generateProcessors() + + extensions := cfgInput.generateExtensions() + + receivers := cfgInput.generateReceivers() + connectors := cfgInput.generateConnectors() pipelines := cfgInput.generateNamedPipelines() @@ -906,14 +1023,21 @@ func (cfgInput *OtelColConfigInput) AssembleConfig(ctx context.Context) otelv1be } } + extensionNames := make([]string, 0, len(extensions)) + for k := range extensions { + extensionNames = append(extensionNames, k) + } + return otelv1beta1.Config{ Receivers: otelv1beta1.AnyConfig{Object: receivers}, Exporters: otelv1beta1.AnyConfig{Object: exporters}, Processors: &otelv1beta1.AnyConfig{Object: processors}, Connectors: &otelv1beta1.AnyConfig{Object: connectors}, + Extensions: &otelv1beta1.AnyConfig{Object: extensions}, Service: otelv1beta1.Service{ - Telemetry: &otelv1beta1.AnyConfig{Object: telemetry}, - Pipelines: pipelines, + Extensions: &extensionNames, + Telemetry: &otelv1beta1.AnyConfig{Object: telemetry}, + Pipelines: pipelines, }, } } diff --git a/internal/controller/telemetry/otel_conf_gen_test.go b/internal/controller/telemetry/otel_conf_gen_test.go index 54c6315f..e82b3a0f 100644 --- a/internal/controller/telemetry/otel_conf_gen_test.go +++ b/internal/controller/telemetry/otel_conf_gen_test.go @@ -27,6 +27,8 @@ import ( "github.com/siliconbrain/go-mapseqs/mapseqs" "github.com/siliconbrain/go-seqs/seqs" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/kube-logging/telemetry-controller/api/telemetry/v1alpha1" @@ -169,66 +171,92 @@ func TestOtelColConfComplex(t *testing.T) { }, }, }, - Outputs: []v1alpha1.Output{ + OutputsWithSecretData: []OutputWithSecretData{ { - ObjectMeta: metav1.ObjectMeta{ - Name: "otlp-test-output", - Namespace: "collector", + Secret: corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "bearer-test-secret", + Namespace: "collector", + }, + Data: map[string][]byte{ + "token": []byte("testtoken"), + }, + Type: "Opaque", }, - Spec: v1alpha1.OutputSpec{ - OTLPGRPC: &v1alpha1.OTLPGRPC{ - GRPCClientConfig: v1alpha1.GRPCClientConfig{ - Endpoint: "receiver-collector.example-tenant-a-ns.svc.cluster.local:4317", - TLSSetting: v1alpha1.TLSClientSetting{ - Insecure: true, + Output: v1alpha1.Output{ + ObjectMeta: metav1.ObjectMeta{ + Name: "otlp-test-output", + Namespace: "collector", + }, + Spec: v1alpha1.OutputSpec{ + OTLPGRPC: &v1alpha1.OTLPGRPC{ + GRPCClientConfig: v1alpha1.GRPCClientConfig{ + Endpoint: "receiver-collector.example-tenant-a-ns.svc.cluster.local:4317", + TLSSetting: v1alpha1.TLSClientSetting{ + Insecure: true, + }, + }, + }, + Authentication: &v1alpha1.OutputAuth{ + BearerAuth: &v1alpha1.BearerAuthConfig{ + SecretRef: &v1.SecretReference{ + Name: "bearer-test-secret", + Namespace: "collector", + }, }, }, }, }, }, { - ObjectMeta: metav1.ObjectMeta{ - Name: "otlp-test-output-2", - Namespace: "collector", - }, - Spec: v1alpha1.OutputSpec{ - OTLPGRPC: &v1alpha1.OTLPGRPC{ - GRPCClientConfig: v1alpha1.GRPCClientConfig{ - Endpoint: "receiver-collector.example-tenant-a-ns.svc.cluster.local:4317", - TLSSetting: v1alpha1.TLSClientSetting{ - Insecure: true, + Output: v1alpha1.Output{ + ObjectMeta: metav1.ObjectMeta{ + Name: "otlp-test-output-2", + Namespace: "collector", + }, + Spec: v1alpha1.OutputSpec{ + OTLPGRPC: &v1alpha1.OTLPGRPC{ + GRPCClientConfig: v1alpha1.GRPCClientConfig{ + Endpoint: "receiver-collector.example-tenant-a-ns.svc.cluster.local:4317", + TLSSetting: v1alpha1.TLSClientSetting{ + Insecure: true, + }, }, }, }, }, }, { - ObjectMeta: metav1.ObjectMeta{ - Name: "loki-test-output", - Namespace: "collector", - }, - Spec: v1alpha1.OutputSpec{ - OTLPHTTP: &v1alpha1.OTLPHTTP{ - HTTPClientConfig: v1alpha1.HTTPClientConfig{ - Endpoint: "loki.example-tenant-a-ns.svc.cluster.local:4317", - TLSSetting: v1alpha1.TLSClientSetting{ - Insecure: true, + Output: v1alpha1.Output{ + ObjectMeta: metav1.ObjectMeta{ + Name: "loki-test-output", + Namespace: "collector", + }, + Spec: v1alpha1.OutputSpec{ + OTLPHTTP: &v1alpha1.OTLPHTTP{ + HTTPClientConfig: v1alpha1.HTTPClientConfig{ + Endpoint: "loki.example-tenant-a-ns.svc.cluster.local:4317", + TLSSetting: v1alpha1.TLSClientSetting{ + Insecure: true, + }, }, }, }, }, }, { - ObjectMeta: metav1.ObjectMeta{ - Name: "fluentforward-test-output", - Namespace: "collector", - }, - Spec: v1alpha1.OutputSpec{ - Fluentforward: &v1alpha1.Fluentforward{ - TCPClientSettings: v1alpha1.TCPClientSettings{ - Endpoint: "fluentforward.example-tenant-ns.svc.cluster.local:8888", - TLSSetting: v1alpha1.TLSClientSetting{ - Insecure: true, + Output: v1alpha1.Output{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fluentforward-test-output", + Namespace: "collector", + }, + Spec: v1alpha1.OutputSpec{ + Fluentforward: &v1alpha1.Fluentforward{ + TCPClientSettings: v1alpha1.TCPClientSettings{ + Endpoint: "fluentforward.example-tenant-ns.svc.cluster.local:8888", + TLSSetting: v1alpha1.TLSClientSetting{ + Insecure: true, + }, }, }, }, @@ -315,7 +343,7 @@ func TestOtelColConfigInput_generateRoutingConnectorForTenantsSubscription(t *te type fields struct { Tenants []v1alpha1.Tenant Subscriptions map[v1alpha1.NamespacedName]v1alpha1.Subscription - Outputs []v1alpha1.Output + OutputsWithSecretData []OutputWithSecretData TenantSubscriptionMap map[string][]v1alpha1.NamespacedName SubscriptionOutputMap map[v1alpha1.NamespacedName][]v1alpha1.NamespacedName } @@ -374,7 +402,7 @@ func TestOtelColConfigInput_generateRoutingConnectorForTenantsSubscription(t *te }, OTTL: `set(attributes["subscription"], "subscriptionB")`}, }, }, - Outputs: []v1alpha1.Output{}, + OutputsWithSecretData: []OutputWithSecretData{}, TenantSubscriptionMap: map[string][]v1alpha1.NamespacedName{ "tenantA": { { @@ -417,12 +445,13 @@ func TestOtelColConfigInput_generateRoutingConnectorForTenantsSubscription(t *te }, }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfgInput := &OtelColConfigInput{ Tenants: tt.fields.Tenants, Subscriptions: tt.fields.Subscriptions, - Outputs: tt.fields.Outputs, + OutputsWithSecretData: tt.fields.OutputsWithSecretData, TenantSubscriptionMap: tt.fields.TenantSubscriptionMap, SubscriptionOutputMap: tt.fields.SubscriptionOutputMap, } From 14a2f137c7054e98ab865b94ac2194565cf37f2e Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Mon, 7 Oct 2024 09:11:30 +0200 Subject: [PATCH 2/5] watch secrets and reconcile collectors on changes Signed-off-by: Kristof Gyuracz --- .../telemetry/collector_controller.go | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index fad0830c..345e3834 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -282,12 +282,12 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { collectors := &v1alpha1.CollectorList{} err := r.List(ctx, collectors) if err != nil { - logger.Error(errors.WithStack(err), "failed listing tenants for mapping requests, unable to send requests") + logger.Error(errors.WithStack(err), "failed listing collectors for mapping requests, unable to send requests") return } - for _, tenant := range collectors.Items { - requests = addCollectorRequest(requests, tenant.Name) + for _, collector := range collectors.Items { + requests = addCollectorRequest(requests, collector.Name) } return @@ -298,12 +298,12 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { collectors := &v1alpha1.CollectorList{} err := r.List(ctx, collectors) if err != nil { - logger.Error(errors.WithStack(err), "failed listing tenants for mapping requests, unable to send requests") + logger.Error(errors.WithStack(err), "failed listing collectors for mapping requests, unable to send requests") return } - for _, tenant := range collectors.Items { - requests = addCollectorRequest(requests, tenant.Name) + for _, collector := range collectors.Items { + requests = addCollectorRequest(requests, collector.Name) } return @@ -314,12 +314,12 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { collectors := &v1alpha1.CollectorList{} err := r.List(ctx, collectors) if err != nil { - logger.Error(errors.WithStack(err), "failed listing tenants for mapping requests, unable to send requests") + logger.Error(errors.WithStack(err), "failed listing collectors for mapping requests, unable to send requests") return } - for _, tenant := range collectors.Items { - requests = addCollectorRequest(requests, tenant.Name) + for _, collector := range collectors.Items { + requests = addCollectorRequest(requests, collector.Name) } return @@ -330,12 +330,28 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { collectors := &v1alpha1.CollectorList{} err := r.List(ctx, collectors) if err != nil { - logger.Error(errors.WithStack(err), "failed listing tenants for mapping requests, unable to send requests") + logger.Error(errors.WithStack(err), "failed listing collectors for mapping requests, unable to send requests") return } - for _, tenant := range collectors.Items { - requests = addCollectorRequest(requests, tenant.Name) + for _, collector := range collectors.Items { + requests = addCollectorRequest(requests, collector.Name) + } + + return + })). + Watches(&corev1.Secret{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, object client.Object) (requests []reconcile.Request) { + logger := log.FromContext(ctx) + + collectors := &v1alpha1.CollectorList{} + err := r.List(ctx, collectors) + if err != nil { + logger.Error(errors.WithStack(err), "failed listing collectors for mapping requests, unable to send requests") + return + } + + for _, collector := range collectors.Items { + requests = addCollectorRequest(requests, collector.Name) } return From 2ee88ee682ada6ef801b3eff02dc020533fb8a8d Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Mon, 7 Oct 2024 09:35:47 +0200 Subject: [PATCH 3/5] refactor Signed-off-by: Kristof Gyuracz --- .../telemetry/collector_controller.go | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 345e3834..3eb16451 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -110,21 +110,8 @@ func (r *CollectorReconciler) buildConfigInputForCollector(ctx context.Context, } outputWithSecretData.Output = *queriedOutput - if queriedOutput.Spec.Authentication != nil { - if queriedOutput.Spec.Authentication.BasicAuth != nil && queriedOutput.Spec.Authentication.BasicAuth.SecretRef != nil { - queriedSecret := &corev1.Secret{} - if err = r.Client.Get(ctx, types.NamespacedName{Namespace: queriedOutput.Spec.Authentication.BasicAuth.SecretRef.Namespace, Name: queriedOutput.Spec.Authentication.BasicAuth.SecretRef.Name}, queriedSecret); err != nil { - logger.Error(errors.WithStack(err), "failed getting secrets for output", "output", queriedOutput.NamespacedName().String()) - } - outputWithSecretData.Secret = *queriedSecret - } - if queriedOutput.Spec.Authentication.BearerAuth != nil && queriedOutput.Spec.Authentication.BearerAuth.SecretRef != nil { - queriedSecret := &corev1.Secret{} - if err = r.Client.Get(ctx, types.NamespacedName{Namespace: queriedOutput.Spec.Authentication.BearerAuth.SecretRef.Namespace, Name: queriedOutput.Spec.Authentication.BearerAuth.SecretRef.Name}, queriedSecret); err != nil { - logger.Error(errors.WithStack(err), "failed getting secrets for output", "output", queriedOutput.NamespacedName().String()) - } - outputWithSecretData.Secret = *queriedSecret - } + if err := r.populateSecretForOutput(ctx, queriedOutput, &outputWithSecretData); err != nil { + return OtelColConfigInput{}, err } outputs = append(outputs, outputWithSecretData) @@ -144,6 +131,31 @@ func (r *CollectorReconciler) buildConfigInputForCollector(ctx context.Context, return otelConfigInput, nil } +func (r *CollectorReconciler) populateSecretForOutput(ctx context.Context, queriedOutput *v1alpha1.Output, outputWithSecret *OutputWithSecretData) error { + logger := log.FromContext(ctx) + + if queriedOutput.Spec.Authentication != nil { + if queriedOutput.Spec.Authentication.BasicAuth != nil && queriedOutput.Spec.Authentication.BasicAuth.SecretRef != nil { + queriedSecret := &corev1.Secret{} + if err := r.Client.Get(ctx, types.NamespacedName{Namespace: queriedOutput.Spec.Authentication.BasicAuth.SecretRef.Namespace, Name: queriedOutput.Spec.Authentication.BasicAuth.SecretRef.Name}, queriedSecret); err != nil { + logger.Error(errors.WithStack(err), "failed getting secrets for output", "output", queriedOutput.NamespacedName().String()) + return err + } + outputWithSecret.Secret = *queriedSecret + } + if queriedOutput.Spec.Authentication.BearerAuth != nil && queriedOutput.Spec.Authentication.BearerAuth.SecretRef != nil { + queriedSecret := &corev1.Secret{} + if err := r.Client.Get(ctx, types.NamespacedName{Namespace: queriedOutput.Spec.Authentication.BearerAuth.SecretRef.Namespace, Name: queriedOutput.Spec.Authentication.BearerAuth.SecretRef.Name}, queriedSecret); err != nil { + logger.Error(errors.WithStack(err), "failed getting secrets for output", "output", queriedOutput.NamespacedName().String()) + return err + } + outputWithSecret.Secret = *queriedSecret + } + } + + return nil +} + // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors;tenants;subscriptions;outputs;,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/status;tenants/status;subscriptions/status;outputs/status;,verbs=get;update;patch // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/finalizers,verbs=update From 5eb97277a09b1b90693edfed4eced9f7081ecc77 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Mon, 7 Oct 2024 10:03:59 +0200 Subject: [PATCH 4/5] fix RBAC role generator and add secret permission Signed-off-by: Kristof Gyuracz --- Makefile | 1 + charts/telemetry-controller/templates/rbac.yaml | 1 + config/rbac/role.yaml | 12 ++++++++++++ .../controller/telemetry/collector_controller.go | 2 +- 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ea09d973..a90f4be4 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,7 @@ help: ## Display this help. .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./api/..." output:crd:artifacts:config=config/crd/bases + $(CONTROLLER_GEN) rbac:roleName=manager-role paths="./internal/controller/telemetry/..." output:rbac:artifacts:config=./config/rbac cp config/crd/bases/* charts/telemetry-controller/crds/ .PHONY: generate diff --git a/charts/telemetry-controller/templates/rbac.yaml b/charts/telemetry-controller/templates/rbac.yaml index 204bf340..39e7dba0 100644 --- a/charts/telemetry-controller/templates/rbac.yaml +++ b/charts/telemetry-controller/templates/rbac.yaml @@ -50,6 +50,7 @@ rules: - namespaces - nodes - nodes/proxy + - secrets verbs: - get - list diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 1bfed555..9055e3ad 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -15,6 +15,18 @@ rules: - get - list - watch +- apiGroups: + - "" + resources: + - endpoints + - namespaces + - nodes + - nodes/proxy + - secrets + verbs: + - get + - list + - watch - apiGroups: - "" resources: diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 3eb16451..f448c205 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -159,7 +159,7 @@ func (r *CollectorReconciler) populateSecretForOutput(ctx context.Context, queri // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors;tenants;subscriptions;outputs;,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/status;tenants/status;subscriptions/status;outputs/status;,verbs=get;update;patch // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/finalizers,verbs=update -// +kubebuilder:rbac:groups="",resources=nodes;namespaces;endpoints;nodes/proxy,verbs=get;list;watch +// +kubebuilder:rbac:groups="",resources=secrets;nodes;namespaces;endpoints;nodes/proxy,verbs=get;list;watch // +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterroles;clusterrolebindings;roles;rolebindings,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups="",resources=services;persistentvolumeclaims;serviceaccounts;pods,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=apps,resources=statefulsets;daemonsets;replicasets,verbs=get;list;watch;create;update;patch;delete From 7699430360be5273e285f0fb4fd2e05a78d5c424 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Mon, 7 Oct 2024 10:09:48 +0200 Subject: [PATCH 5/5] add example basicauth config Signed-off-by: Kristof Gyuracz --- .../simple-demo-with-secretref/certs.yaml | 60 +++++++++++++++ .../simple-demo-with-secretref/pipeline.yaml | 74 +++++++++++++++++++ .../simple-demo-with-secretref/receiver.yaml | 44 +++++++++++ 3 files changed, 178 insertions(+) create mode 100644 docs/examples/simple-demo-with-secretref/certs.yaml create mode 100644 docs/examples/simple-demo-with-secretref/pipeline.yaml create mode 100644 docs/examples/simple-demo-with-secretref/receiver.yaml diff --git a/docs/examples/simple-demo-with-secretref/certs.yaml b/docs/examples/simple-demo-with-secretref/certs.yaml new file mode 100644 index 00000000..9f1ef938 --- /dev/null +++ b/docs/examples/simple-demo-with-secretref/certs.yaml @@ -0,0 +1,60 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: receiver +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: selfsigned-issuer +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: my-selfsigned-ca + namespace: cert-manager +spec: + isCA: true + commonName: my-selfsigned-ca # deprecated but still requires in iOS environment + secretName: root-secret + subject: # needed later for local trust store + organizations: + - example.com + privateKey: + algorithm: ECDSA + size: 256 + issuerRef: + name: selfsigned-issuer + kind: ClusterIssuer + group: cert-manager.io +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: my-ca-issuer +spec: + ca: + secretName: root-secret +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: server-certs + namespace: receiver +spec: + secretName: server-certs + dnsNames: + - localhost + ipAddresses: + - 127.0.0.1 + - ::1 + privateKey: + algorithm: RSA + encoding: PKCS8 + size: 2048 + issuerRef: + name: my-ca-issuer + kind: ClusterIssuer + group: cert-manager.io diff --git a/docs/examples/simple-demo-with-secretref/pipeline.yaml b/docs/examples/simple-demo-with-secretref/pipeline.yaml new file mode 100644 index 00000000..2cc20426 --- /dev/null +++ b/docs/examples/simple-demo-with-secretref/pipeline.yaml @@ -0,0 +1,74 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: collector +--- +apiVersion: v1 +kind: Namespace +metadata: + labels: + nsSelector: example-tenant + name: example-tenant-ns +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Collector +metadata: + name: example-collector +spec: + debug: true + controlNamespace: collector + tenantSelector: + matchLabels: + collectorLabel: example-collector +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Tenant +metadata: + labels: + collectorLabel: example-collector + name: example-tenant +spec: + subscriptionNamespaceSelectors: + - matchLabels: + nsSelector: example-tenant + logSourceNamespaceSelectors: + - matchLabels: + nsSelector: example-tenant +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Subscription +metadata: + name: subscription-sample-1 + namespace: example-tenant-ns +spec: + ottl: "route()" + outputs: + - name: otlp-test-output-1 + namespace: collector +--- +apiVersion: v1 +kind: Secret +metadata: + name: otlp-test-output-1-basicauth-token-secret + namespace: collector +type: Opaque +data: + username: dXNlcg== # user + password: cGFzcw== # pass +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Output +metadata: + name: otlp-test-output-1 + namespace: collector +spec: + authentication: + basicauth: + secretRef: + name: otlp-test-output-1-basicauth-token-secret + namespace: collector + otlp: + endpoint: receiver-otelcol-collector.receiver.svc.cluster.local:4317 + tls: + insecure: false + insecure_skip_verify: true diff --git a/docs/examples/simple-demo-with-secretref/receiver.yaml b/docs/examples/simple-demo-with-secretref/receiver.yaml new file mode 100644 index 00000000..6aa25748 --- /dev/null +++ b/docs/examples/simple-demo-with-secretref/receiver.yaml @@ -0,0 +1,44 @@ +apiVersion: opentelemetry.io/v1beta1 +kind: OpenTelemetryCollector +metadata: + name: receiver-otelcol + namespace: receiver +spec: + image: otel/opentelemetry-collector-contrib:0.104.0 + volumes: + - name: certs-volume + secret: + secretName: server-certs + volumeMounts: + - mountPath: "/certs" + name: certs-volume + readOnly: true + config: + extensions: + basicauth: + htpasswd: + inline: | + user:pass + receivers: + otlp: + protocols: + grpc: + auth: + authenticator: basicauth + tls: + cert_file: /certs/tls.crt + key_file: /certs/tls.key + ca_file: /certs/ca.crt + exporters: + debug: + verbosity: detailed + service: + telemetry: + logs: + level: "debug" + extensions: [basicauth] + pipelines: + logs: + processors: [] + receivers: [otlp] + exporters: [debug]