diff --git a/.env b/.env index b36e569440..2cda8727b1 100644 --- a/.env +++ b/.env @@ -18,6 +18,8 @@ ENV_GORELEASER_VERSION=v1.23.0 ENV_FLUENTBIT_EXPORTER_IMAGE="europe-docker.pkg.dev/kyma-project/prod/directory-size-exporter:v20251210-3d7f23ad" ENV_FLUENTBIT_IMAGE="europe-docker.pkg.dev/kyma-project/prod/external/fluent/fluent-bit:4.2.2" ENV_OTEL_COLLECTOR_IMAGE="europe-docker.pkg.dev/kyma-project/prod/kyma-otel-collector:0.141.0-main" +# ENV_OTEL_COLLECTOR_CONTRIB_IMAGE is used for OAuth2 E2E tests only, since they require the OIDC extension, which is not needed in production code. +ENV_OTEL_COLLECTOR_CONTRIB_IMAGE="otel/opentelemetry-collector-contrib:latest" ENV_SELFMONITOR_IMAGE="europe-docker.pkg.dev/kyma-project/prod/tpi/telemetry-self-monitor:3.8.0-3d7f23a" ENV_TEST_TELEMETRYGEN_IMAGE="ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:v0.141.0" ENV_ALPINE_IMAGE="europe-docker.pkg.dev/kyma-project/prod/external/library/alpine:3.23.2" diff --git a/apis/telemetry/v1alpha1/shared_types.go b/apis/telemetry/v1alpha1/shared_types.go index 4139fd86f8..857afed492 100644 --- a/apis/telemetry/v1alpha1/shared_types.go +++ b/apis/telemetry/v1alpha1/shared_types.go @@ -41,6 +41,7 @@ const ( // OTLPOutput OTLP output configuration // +kubebuilder:validation:XValidation:rule="(has(self.path) && size(self.path) > 0) ? self.protocol == 'http' : true",message="Path is only available with HTTP protocol" +// +kubebuilder:validation:XValidation:rule="(has(self.authentication) && has(self.authentication.oauth2) && self.protocol == 'grpc' && has(self.tls)) ? !(has(self.tls.insecure) && self.tls.insecure == true) : true",message="OAuth2 authentication requires TLS when using gRPC protocol" type OTLPOutput struct { // Protocol defines the OTLP protocol (`http` or `grpc`). Default is `grpc`. // +kubebuilder:validation:Optional @@ -63,10 +64,15 @@ type OTLPOutput struct { TLS *OTLPTLS `json:"tls,omitempty"` } +// AuthenticationOptions OTLP output authentication options +// +kubebuilder:validation:XValidation:rule="!(has(self.basic) && has(self.oauth2))",message="Only one authentication method can be specified" type AuthenticationOptions struct { // Basic activates `Basic` authentication for the destination providing relevant Secrets. // +kubebuilder:validation:Optional Basic *BasicAuthOptions `json:"basic,omitempty"` + // OAuth2 activates `OAuth2` authentication for the destination providing relevant Secrets. + // +kubebuilder:validation:Optional + OAuth2 *OAuth2Options `json:"oauth2,omitempty"` } type BasicAuthOptions struct { @@ -78,6 +84,26 @@ type BasicAuthOptions struct { Password ValueType `json:"password"` } +// OAuth2Options contains OAuth2 authentication options. +type OAuth2Options struct { + // TokenURL contains the OAuth2 token endpoint URL or a Secret reference. + // +kubebuilder:validation:XValidation:rule="(self.value != '' ) || (has(self.valueFrom))", message="tokenURL' missing" + // +kubebuilder:validation:XValidation:rule="(self.value != '' ) ? (isURL(self.value)) : true", message="'tokenURL' must be a valid URL" + TokenURL ValueType `json:"tokenURL"` + // ClientID contains the OAuth2 client ID or a Secret reference. + // +kubebuilder:validation:XValidation:rule="(self.value != '' ) || (has(self.valueFrom))", message="'clientID' missing" + ClientID ValueType `json:"clientID"` + // ClientSecret contains the OAuth2 client secret or a Secret reference. + // +kubebuilder:validation:XValidation:rule="(self.value != '' ) || (has(self.valueFrom))", message="clientSecret' missing" + ClientSecret ValueType `json:"clientSecret"` + // Scopes contains optional OAuth2 scopes. + // +kubebuilder:validation:Optional + Scopes []string `json:"scopes,omitempty"` + // Params contains optional additional OAuth2 parameters that are sent to the token endpoint. + // +kubebuilder:validation:Optional + Params map[string]string `json:"params,omitempty"` +} + type Header struct { // Defines the header value. ValueType `json:",inline"` diff --git a/apis/telemetry/v1alpha1/zz_generated.conversion.go b/apis/telemetry/v1alpha1/zz_generated.conversion.go index 871a546158..e57e24e8a2 100644 --- a/apis/telemetry/v1alpha1/zz_generated.conversion.go +++ b/apis/telemetry/v1alpha1/zz_generated.conversion.go @@ -301,6 +301,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*OAuth2Options)(nil), (*v1beta1.OAuth2Options)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_OAuth2Options_To_v1beta1_OAuth2Options(a.(*OAuth2Options), b.(*v1beta1.OAuth2Options), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta1.OAuth2Options)(nil), (*OAuth2Options)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_OAuth2Options_To_v1alpha1_OAuth2Options(a.(*v1beta1.OAuth2Options), b.(*OAuth2Options), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*OTLPOutput)(nil), (*v1beta1.OTLPOutput)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_OTLPOutput_To_v1beta1_OTLPOutput(a.(*OTLPOutput), b.(*v1beta1.OTLPOutput), scope) }); err != nil { @@ -441,6 +451,7 @@ func RegisterConversions(s *runtime.Scheme) error { func autoConvert_v1alpha1_AuthenticationOptions_To_v1beta1_AuthenticationOptions(in *AuthenticationOptions, out *v1beta1.AuthenticationOptions, s conversion.Scope) error { out.Basic = (*v1beta1.BasicAuthOptions)(unsafe.Pointer(in.Basic)) + out.OAuth2 = (*v1beta1.OAuth2Options)(unsafe.Pointer(in.OAuth2)) return nil } @@ -451,6 +462,7 @@ func Convert_v1alpha1_AuthenticationOptions_To_v1beta1_AuthenticationOptions(in func autoConvert_v1beta1_AuthenticationOptions_To_v1alpha1_AuthenticationOptions(in *v1beta1.AuthenticationOptions, out *AuthenticationOptions, s conversion.Scope) error { out.Basic = (*BasicAuthOptions)(unsafe.Pointer(in.Basic)) + out.OAuth2 = (*OAuth2Options)(unsafe.Pointer(in.OAuth2)) return nil } @@ -1252,6 +1264,46 @@ func Convert_v1beta1_NamespaceSelector_To_v1alpha1_NamespaceSelector(in *v1beta1 return autoConvert_v1beta1_NamespaceSelector_To_v1alpha1_NamespaceSelector(in, out, s) } +func autoConvert_v1alpha1_OAuth2Options_To_v1beta1_OAuth2Options(in *OAuth2Options, out *v1beta1.OAuth2Options, s conversion.Scope) error { + if err := Convert_v1alpha1_ValueType_To_v1beta1_ValueType(&in.TokenURL, &out.TokenURL, s); err != nil { + return err + } + if err := Convert_v1alpha1_ValueType_To_v1beta1_ValueType(&in.ClientID, &out.ClientID, s); err != nil { + return err + } + if err := Convert_v1alpha1_ValueType_To_v1beta1_ValueType(&in.ClientSecret, &out.ClientSecret, s); err != nil { + return err + } + out.Scopes = *(*[]string)(unsafe.Pointer(&in.Scopes)) + out.Params = *(*map[string]string)(unsafe.Pointer(&in.Params)) + return nil +} + +// Convert_v1alpha1_OAuth2Options_To_v1beta1_OAuth2Options is an autogenerated conversion function. +func Convert_v1alpha1_OAuth2Options_To_v1beta1_OAuth2Options(in *OAuth2Options, out *v1beta1.OAuth2Options, s conversion.Scope) error { + return autoConvert_v1alpha1_OAuth2Options_To_v1beta1_OAuth2Options(in, out, s) +} + +func autoConvert_v1beta1_OAuth2Options_To_v1alpha1_OAuth2Options(in *v1beta1.OAuth2Options, out *OAuth2Options, s conversion.Scope) error { + if err := Convert_v1beta1_ValueType_To_v1alpha1_ValueType(&in.TokenURL, &out.TokenURL, s); err != nil { + return err + } + if err := Convert_v1beta1_ValueType_To_v1alpha1_ValueType(&in.ClientID, &out.ClientID, s); err != nil { + return err + } + if err := Convert_v1beta1_ValueType_To_v1alpha1_ValueType(&in.ClientSecret, &out.ClientSecret, s); err != nil { + return err + } + out.Scopes = *(*[]string)(unsafe.Pointer(&in.Scopes)) + out.Params = *(*map[string]string)(unsafe.Pointer(&in.Params)) + return nil +} + +// Convert_v1beta1_OAuth2Options_To_v1alpha1_OAuth2Options is an autogenerated conversion function. +func Convert_v1beta1_OAuth2Options_To_v1alpha1_OAuth2Options(in *v1beta1.OAuth2Options, out *OAuth2Options, s conversion.Scope) error { + return autoConvert_v1beta1_OAuth2Options_To_v1alpha1_OAuth2Options(in, out, s) +} + func autoConvert_v1alpha1_OTLPInput_To_v1beta1_OTLPInput(in *OTLPInput, out *v1beta1.OTLPInput, s conversion.Scope) error { // WARNING: in.Disabled requires manual conversion: does not exist in peer-type out.Namespaces = (*v1beta1.NamespaceSelector)(unsafe.Pointer(in.Namespaces)) diff --git a/apis/telemetry/v1alpha1/zz_generated.deepcopy.go b/apis/telemetry/v1alpha1/zz_generated.deepcopy.go index de6f29d719..4783993911 100644 --- a/apis/telemetry/v1alpha1/zz_generated.deepcopy.go +++ b/apis/telemetry/v1alpha1/zz_generated.deepcopy.go @@ -33,6 +33,11 @@ func (in *AuthenticationOptions) DeepCopyInto(out *AuthenticationOptions) { *out = new(BasicAuthOptions) (*in).DeepCopyInto(*out) } + if in.OAuth2 != nil { + in, out := &in.OAuth2, &out.OAuth2 + *out = new(OAuth2Options) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationOptions. @@ -874,6 +879,36 @@ func (in *NamespaceSelector) DeepCopy() *NamespaceSelector { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OAuth2Options) DeepCopyInto(out *OAuth2Options) { + *out = *in + in.TokenURL.DeepCopyInto(&out.TokenURL) + in.ClientID.DeepCopyInto(&out.ClientID) + in.ClientSecret.DeepCopyInto(&out.ClientSecret) + if in.Scopes != nil { + in, out := &in.Scopes, &out.Scopes + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Params != nil { + in, out := &in.Params, &out.Params + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAuth2Options. +func (in *OAuth2Options) DeepCopy() *OAuth2Options { + if in == nil { + return nil + } + out := new(OAuth2Options) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OTLPInput) DeepCopyInto(out *OTLPInput) { *out = *in diff --git a/apis/telemetry/v1beta1/shared_types.go b/apis/telemetry/v1beta1/shared_types.go index 8d4e0bb685..6fa9510199 100644 --- a/apis/telemetry/v1beta1/shared_types.go +++ b/apis/telemetry/v1beta1/shared_types.go @@ -43,6 +43,7 @@ const ( // OTLPOutput OTLP output configuration // +kubebuilder:validation:XValidation:rule="(has(self.path) && size(self.path) > 0) ? self.protocol == 'http' : true",message="Path is only available with HTTP protocol" +// +kubebuilder:validation:XValidation:rule="(has(self.authentication) && has(self.authentication.oauth2) && self.protocol == 'grpc' && has(self.tls)) ? !(has(self.tls.insecure) && self.tls.insecure == true) : true",message="OAuth2 authentication requires TLS when using gRPC protocol" type OTLPOutput struct { // Protocol defines the OTLP protocol (`http` or `grpc`). Default is `grpc`. // +kubebuilder:validation:Optional @@ -65,10 +66,15 @@ type OTLPOutput struct { TLS *OutputTLS `json:"tls,omitempty"` } +// AuthenticationOptions OTLP output authentication options +// +kubebuilder:validation:XValidation:rule="!(has(self.basic) && has(self.oauth2))",message="Only one authentication method can be specified" type AuthenticationOptions struct { // Basic activates `Basic` authentication for the destination providing relevant Secrets. // +kubebuilder:validation:Optional Basic *BasicAuthOptions `json:"basic,omitempty"` + // OAuth2 activates `OAuth2` authentication for the destination providing relevant Secrets. + // +kubebuilder:validation:Optional + OAuth2 *OAuth2Options `json:"oauth2,omitempty"` } type BasicAuthOptions struct { @@ -80,6 +86,24 @@ type BasicAuthOptions struct { Password ValueType `json:"password"` } +type OAuth2Options struct { + // TokenURL contains the OAuth2 token endpoint URL or a Secret reference. + // +kubebuilder:validation:Required + TokenURL ValueType `json:"tokenURL"` + // ClientID contains the OAuth2 client ID or a Secret reference. + // +kubebuilder:validation:Required + ClientID ValueType `json:"clientID"` + // ClientSecret contains the OAuth2 client secret or a Secret reference. + // +kubebuilder:validation:Required + ClientSecret ValueType `json:"clientSecret"` + // Scopes contains optional OAuth2 scopes. + // +kubebuilder:validation:Optional + Scopes []string `json:"scopes,omitempty"` + // Params contains optional additional OAuth2 parameters that are sent to the token endpoint. + // +kubebuilder:validation:Optional + Params map[string]string `json:"params,omitempty"` +} + type Header struct { // Defines the header value. ValueType `json:",inline"` diff --git a/apis/telemetry/v1beta1/zz_generated.deepcopy.go b/apis/telemetry/v1beta1/zz_generated.deepcopy.go index 60347d5b17..6f1aa17d57 100644 --- a/apis/telemetry/v1beta1/zz_generated.deepcopy.go +++ b/apis/telemetry/v1beta1/zz_generated.deepcopy.go @@ -33,6 +33,11 @@ func (in *AuthenticationOptions) DeepCopyInto(out *AuthenticationOptions) { *out = new(BasicAuthOptions) (*in).DeepCopyInto(*out) } + if in.OAuth2 != nil { + in, out := &in.OAuth2, &out.OAuth2 + *out = new(OAuth2Options) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationOptions. @@ -827,6 +832,36 @@ func (in *NamespaceSelector) DeepCopy() *NamespaceSelector { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OAuth2Options) DeepCopyInto(out *OAuth2Options) { + *out = *in + in.TokenURL.DeepCopyInto(&out.TokenURL) + in.ClientID.DeepCopyInto(&out.ClientID) + in.ClientSecret.DeepCopyInto(&out.ClientSecret) + if in.Scopes != nil { + in, out := &in.Scopes, &out.Scopes + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Params != nil { + in, out := &in.Params, &out.Params + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAuth2Options. +func (in *OAuth2Options) DeepCopy() *OAuth2Options { + if in == nil { + return nil + } + out := new(OAuth2Options) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OTLPInput) DeepCopyInto(out *OTLPInput) { *out = *in diff --git a/dependencies/populateimages/main.go b/dependencies/populateimages/main.go index 6c8a0e9417..2da61b2438 100644 --- a/dependencies/populateimages/main.go +++ b/dependencies/populateimages/main.go @@ -18,8 +18,9 @@ var templates = map[string]string{ package testkit const ( - DefaultTelemetryGenImage = "{{ .ENV_TEST_TELEMETRYGEN_IMAGE }}" - DefaultOTelCollectorImage = "{{ .ENV_OTEL_COLLECTOR_IMAGE }}" + DefaultTelemetryGenImage = "{{ .ENV_TEST_TELEMETRYGEN_IMAGE }}" + DefaultOTelCollectorContribImage = "{{ .ENV_OTEL_COLLECTOR_CONTRIB_IMAGE }}" + DefaultOTelCollectorImage = "{{ .ENV_OTEL_COLLECTOR_IMAGE }}" ) `, } diff --git a/docs/user/integrate-otlp-backend/README.md b/docs/user/integrate-otlp-backend/README.md index 21d71f667f..cde184d47e 100644 --- a/docs/user/integrate-otlp-backend/README.md +++ b/docs/user/integrate-otlp-backend/README.md @@ -40,7 +40,7 @@ Ensure the port in your endpoint URL is correct for the chosen protocol. ## Set Up Authentication -For each pipeline, add authentication details (like user names, passwords, certificates, or tokens) to connect securely to your observability backend. You can use mutual TLS (mTLS), custom headers, or Basic Authentication. +For each pipeline, add authentication details (like user names, passwords, certificates, or tokens) to connect securely to your observability backend. You can use mutual TLS (mTLS), custom headers, OAuth2, or Basic Authentication. While you can choose to add your authentication details from plain text, it’s recommended to store these sensitive details in a Kubernetes `Secret` and reference the Secret's keys in your pipeline configuration. When you rotate the `Secret` and update its values, Telemetry Manager detects the changes and applies the new `Secret` to your setup. @@ -88,6 +88,43 @@ While you can choose to add your authentication details from plain text, it’s key: token ``` +- To use OAuth2 for authentication, configure the `authentication.oauth2` section. + + ```yaml + ... + output: + otlp: + endpoint: + valueFrom: + secretKeyRef: + name: backend + namespace: default + key: endpoint + authentication: + oauth2: + clientId: + valueFrom: + secretKeyRef: + name: backend + namespace: default + key: clientId + clientSecret: + valueFrom: + secretKeyRef: + name: backend + namespace: default + key: clientSecret + tokenUrl: + valueFrom: + secretKeyRef: + name: backend + namespace: default + key: tokenUrl + ``` + +> [!NOTE] +> If you want to use OAuth2 with gRPC, you must configure TLS for your backend connection as well. + - To use a username and password for authentication, configure the `authentication.basic` section. ```yaml diff --git a/docs/user/resources/02-logpipeline.md b/docs/user/resources/02-logpipeline.md index 3e054b91cc..fd72b850ff 100644 --- a/docs/user/resources/02-logpipeline.md +++ b/docs/user/resources/02-logpipeline.md @@ -198,6 +198,30 @@ For details, see the [LogPipeline specification file](https://github.com/kyma-pr | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2** | object | OAuth2 activates `OAuth2` authentication for the destination providing relevant Secrets. | +| **output.​otlp.​authentication.​oauth2.​clientID** (required) | object | ClientID contains the OAuth2 client ID or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​clientID.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret** (required) | object | ClientSecret contains the OAuth2 client secret or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2.​params** | map\[string\]string | Params contains optional additional OAuth2 parameters that are sent to the token endpoint. | +| **output.​otlp.​authentication.​oauth2.​scopes** | \[\]string | Scopes contains optional OAuth2 scopes. | +| **output.​otlp.​authentication.​oauth2.​tokenURL** (required) | object | TokenURL contains the OAuth2 token endpoint URL or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | | **output.​otlp.​endpoint** (required) | object | Endpoint defines the host and port (`:`) of an OTLP endpoint. | | **output.​otlp.​endpoint.​value** | string | Value as plain text. | | **output.​otlp.​endpoint.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | diff --git a/docs/user/resources/04-tracepipeline.md b/docs/user/resources/04-tracepipeline.md index c2ae634b22..d6acb2615a 100644 --- a/docs/user/resources/04-tracepipeline.md +++ b/docs/user/resources/04-tracepipeline.md @@ -82,6 +82,30 @@ For details, see the [TracePipeline specification file](https://github.com/kyma- | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2** | object | OAuth2 activates `OAuth2` authentication for the destination providing relevant Secrets. | +| **output.​otlp.​authentication.​oauth2.​clientID** (required) | object | ClientID contains the OAuth2 client ID or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​clientID.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret** (required) | object | ClientSecret contains the OAuth2 client secret or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2.​params** | map\[string\]string | Params contains optional additional OAuth2 parameters that are sent to the token endpoint. | +| **output.​otlp.​authentication.​oauth2.​scopes** | \[\]string | Scopes contains optional OAuth2 scopes. | +| **output.​otlp.​authentication.​oauth2.​tokenURL** (required) | object | TokenURL contains the OAuth2 token endpoint URL or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | | **output.​otlp.​endpoint** (required) | object | Endpoint defines the host and port (`:`) of an OTLP endpoint. | | **output.​otlp.​endpoint.​value** | string | Value as plain text. | | **output.​otlp.​endpoint.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | diff --git a/docs/user/resources/05-metricpipeline.md b/docs/user/resources/05-metricpipeline.md index 766aba6648..1836df18bd 100644 --- a/docs/user/resources/05-metricpipeline.md +++ b/docs/user/resources/05-metricpipeline.md @@ -139,6 +139,30 @@ For details, see the [MetricPipeline specification file](https://github.com/kyma | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | | **output.​otlp.​authentication.​basic.​user.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2** | object | OAuth2 activates `OAuth2` authentication for the destination providing relevant Secrets. | +| **output.​otlp.​authentication.​oauth2.​clientID** (required) | object | ClientID contains the OAuth2 client ID or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​clientID.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientID.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret** (required) | object | ClientSecret contains the OAuth2 client secret or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​clientSecret.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | +| **output.​otlp.​authentication.​oauth2.​params** | map\[string\]string | Params contains optional additional OAuth2 parameters that are sent to the token endpoint. | +| **output.​otlp.​authentication.​oauth2.​scopes** | \[\]string | Scopes contains optional OAuth2 scopes. | +| **output.​otlp.​authentication.​oauth2.​tokenURL** (required) | object | TokenURL contains the OAuth2 token endpoint URL or a Secret reference. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​value** | string | Value as plain text. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef** (required) | object | SecretKeyRef refers to the value of a specific key in a Secret. You must provide `name` and `namespace` of the Secret, as well as the name of the `key`. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​key** (required) | string | Key defines the name of the attribute of the Secret holding the referenced value. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​name** (required) | string | Name of the Secret containing the referenced value. | +| **output.​otlp.​authentication.​oauth2.​tokenURL.​valueFrom.​secretKeyRef.​namespace** (required) | string | Namespace containing the Secret with the referenced value. | | **output.​otlp.​endpoint** (required) | object | Endpoint defines the host and port (`:`) of an OTLP endpoint. | | **output.​otlp.​endpoint.​value** | string | Value as plain text. | | **output.​otlp.​endpoint.​valueFrom** | object | ValueFrom is the value as a reference to a resource. | diff --git a/helm/charts/default/templates/telemetry.kyma-project.io_logpipelines.yaml b/helm/charts/default/templates/telemetry.kyma-project.io_logpipelines.yaml index b45e6cd114..c4189167c1 100644 --- a/helm/charts/default/templates/telemetry.kyma-project.io_logpipelines.yaml +++ b/helm/charts/default/templates/telemetry.kyma-project.io_logpipelines.yaml @@ -689,7 +689,180 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: '''clientID'' missing' + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: clientSecret' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: tokenURL' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: '''tokenURL'' must be a valid URL' + rule: '(self.value != '''' ) ? (isURL(self.value)) + : true' + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -961,6 +1134,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' type: object x-kubernetes-validations: - message: Switching to or away from OTLP output is not supported. diff --git a/helm/charts/default/templates/telemetry.kyma-project.io_metricpipelines.yaml b/helm/charts/default/templates/telemetry.kyma-project.io_metricpipelines.yaml index 1a9c917e87..ed8abafde6 100644 --- a/helm/charts/default/templates/telemetry.kyma-project.io_metricpipelines.yaml +++ b/helm/charts/default/templates/telemetry.kyma-project.io_metricpipelines.yaml @@ -476,7 +476,180 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: '''clientID'' missing' + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: clientSecret' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: tokenURL' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: '''tokenURL'' must be a valid URL' + rule: '(self.value != '''' ) ? (isURL(self.value)) + : true' + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -748,6 +921,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' required: - otlp type: object diff --git a/helm/charts/default/templates/telemetry.kyma-project.io_tracepipelines.yaml b/helm/charts/default/templates/telemetry.kyma-project.io_tracepipelines.yaml index 98429472e0..578205c959 100644 --- a/helm/charts/default/templates/telemetry.kyma-project.io_tracepipelines.yaml +++ b/helm/charts/default/templates/telemetry.kyma-project.io_tracepipelines.yaml @@ -190,7 +190,180 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: '''clientID'' missing' + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: clientSecret' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: tokenURL' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: '''tokenURL'' must be a valid URL' + rule: '(self.value != '''' ) ? (isURL(self.value)) + : true' + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -462,6 +635,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' required: - otlp type: object diff --git a/helm/charts/experimental/templates/telemetry.kyma-project.io_logpipelines.yaml b/helm/charts/experimental/templates/telemetry.kyma-project.io_logpipelines.yaml index a49ae00608..f21097630c 100644 --- a/helm/charts/experimental/templates/telemetry.kyma-project.io_logpipelines.yaml +++ b/helm/charts/experimental/templates/telemetry.kyma-project.io_logpipelines.yaml @@ -689,7 +689,180 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: '''clientID'' missing' + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: clientSecret' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: tokenURL' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: '''tokenURL'' must be a valid URL' + rule: '(self.value != '''' ) ? (isURL(self.value)) + : true' + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -961,6 +1134,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' type: object x-kubernetes-validations: - message: Switching to or away from OTLP output is not supported. @@ -1787,7 +1965,168 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -2060,6 +2399,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' type: object x-kubernetes-validations: - message: Switching to or away from OTLP output is not supported. diff --git a/helm/charts/experimental/templates/telemetry.kyma-project.io_metricpipelines.yaml b/helm/charts/experimental/templates/telemetry.kyma-project.io_metricpipelines.yaml index 39c6b1e837..4113b846ec 100644 --- a/helm/charts/experimental/templates/telemetry.kyma-project.io_metricpipelines.yaml +++ b/helm/charts/experimental/templates/telemetry.kyma-project.io_metricpipelines.yaml @@ -476,7 +476,180 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: '''clientID'' missing' + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: clientSecret' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: tokenURL' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: '''tokenURL'' must be a valid URL' + rule: '(self.value != '''' ) ? (isURL(self.value)) + : true' + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -748,6 +921,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' required: - otlp type: object @@ -1297,7 +1475,168 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -1570,6 +1909,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' required: - otlp type: object diff --git a/helm/charts/experimental/templates/telemetry.kyma-project.io_tracepipelines.yaml b/helm/charts/experimental/templates/telemetry.kyma-project.io_tracepipelines.yaml index 0be09bc427..9b4493fec3 100644 --- a/helm/charts/experimental/templates/telemetry.kyma-project.io_tracepipelines.yaml +++ b/helm/charts/experimental/templates/telemetry.kyma-project.io_tracepipelines.yaml @@ -190,7 +190,180 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: '''clientID'' missing' + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: clientSecret' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: tokenURL' missing + rule: (self.value != '' ) || (has(self.valueFrom)) + - message: '''tokenURL'' must be a valid URL' + rule: '(self.value != '''' ) ? (isURL(self.value)) + : true' + - message: Only one of 'value' or 'valueFrom' can + be set + rule: '!(has(self.value) && size(self.value) > 0 + && has(self.valueFrom))' + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -462,6 +635,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' required: - otlp type: object @@ -724,7 +902,168 @@ spec: - password - user type: object + oauth2: + description: OAuth2 activates `OAuth2` authentication + for the destination providing relevant Secrets. + properties: + clientID: + description: ClientID contains the OAuth2 client ID + or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + clientSecret: + description: ClientSecret contains the OAuth2 client + secret or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + params: + additionalProperties: + type: string + description: Params contains optional additional OAuth2 + parameters that are sent to the token endpoint. + type: object + scopes: + description: Scopes contains optional OAuth2 scopes. + items: + type: string + type: array + tokenURL: + description: TokenURL contains the OAuth2 token endpoint + URL or a Secret reference. + properties: + value: + description: Value as plain text. + type: string + valueFrom: + description: ValueFrom is the value as a reference + to a resource. + properties: + secretKeyRef: + description: SecretKeyRef refers to the value + of a specific key in a Secret. You must + provide `name` and `namespace` of the Secret, + as well as the name of the `key`. + properties: + key: + description: Key defines the name of the + attribute of the Secret holding the + referenced value. + minLength: 1 + type: string + name: + description: Name of the Secret containing + the referenced value. + minLength: 1 + type: string + namespace: + description: Namespace containing the + Secret with the referenced value. + minLength: 1 + type: string + required: + - key + - name + - namespace + type: object + required: + - secretKeyRef + type: object + type: object + x-kubernetes-validations: + - message: Exactly one of 'value' or 'valueFrom' must + be set + rule: has(self.value) != has(self.valueFrom) + required: + - clientID + - clientSecret + - tokenURL + type: object type: object + x-kubernetes-validations: + - message: Only one authentication method can be specified + rule: '!(has(self.basic) && has(self.oauth2))' endpoint: description: Endpoint defines the host and port (`:`) of an OTLP endpoint. @@ -997,6 +1336,11 @@ spec: - message: Path is only available with HTTP protocol rule: '(has(self.path) && size(self.path) > 0) ? self.protocol == ''http'' : true' + - message: OAuth2 authentication requires TLS when using gRPC + protocol + rule: '(has(self.authentication) && has(self.authentication.oauth2) + && self.protocol == ''grpc'' && has(self.tls)) ? !(has(self.tls.insecure) + && self.tls.insecure == true) : true' required: - otlp type: object diff --git a/helm/files/logpipelines-busola-config.yaml b/helm/files/logpipelines-busola-config.yaml index 17fc96d9f6..87450679f4 100644 --- a/helm/files/logpipelines-busola-config.yaml +++ b/helm/files/logpipelines-busola-config.yaml @@ -282,35 +282,96 @@ details: |- widget: Panel visibility: $exists(spec.output.otlp.authentication) children: - - name: User + - name: Basic widget: Panel - visibility: $exists(spec.output.otlp.authentication.basic.user) + visibility: $exists(spec.output.otlp.authentication.basic) children: - - name: Value - source: spec.output.otlp.authentication.basic.user.value - visibility: $exists(spec.output.otlp.authentication.basic.user.value) - - name: Value From Secret - widget: ResourceRefs - source: >- - spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef - kind: Secret - visibility: >- - $exists(spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name) - - name: Password + - name: User + widget: Panel + visibility: $exists(spec.output.otlp.authentication.basic.user) + children: + - name: Value + source: spec.output.otlp.authentication.basic.user.value + visibility: $exists(spec.output.otlp.authentication.basic.user.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name) + - name: Password + widget: Panel + visibility: $exists(spec.output.otlp.authentication.basic.password) + children: + - name: Value + source: spec.output.otlp.authentication.basic.password.value + visibility: >- + $exists(spec.output.otlp.authentication.basic.password.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name) + - name: OAuth2 widget: Panel - visibility: $exists(spec.output.otlp.authentication.basic.password) + visibility: $exists(spec.output.otlp.authentication.oauth2) children: - - name: Value - source: spec.output.otlp.authentication.basic.password.value - visibility: >- - $exists(spec.output.otlp.authentication.basic.password.value) - - name: Value From Secret - widget: ResourceRefs - source: >- - spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef - kind: Secret - visibility: >- - $exists(spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name) + - name: Token URL + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.tokenURL) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.tokenURL.value + visibility: $exists(spec.output.otlp.authentication.oauth2.tokenURL.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef.name) + - name: Client ID + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.clientID) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.clientID.value + visibility: $exists(spec.output.otlp.authentication.oauth2.clientID.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef.name) + - name: Client Secret + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.clientSecret) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.clientSecret.value + visibility: $exists(spec.output.otlp.authentication.oauth2.clientSecret.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef.name) + - name: Scopes + widget: JoinedArray + source: spec.output.otlp.authentication.oauth2.scopes + separator: ', ' + visibility: $exists(spec.output.otlp.authentication.oauth2.scopes) + - name: Params + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.params) + children: + - name: Parameters + source: spec.output.otlp.authentication.oauth2.params - name: Headers widget: Panel visibility: $exists(spec.output.otlp.headers) @@ -691,7 +752,15 @@ form: | path: authentication widget: FormGroup children: + - var: authType + type: string + simple: true + defaultValue: "Basic" + name: Authentication Type + enum: [Basic, OAuth2] + description: Authentication Type defines which authentication method to use for the OTLP endpoint. - name: Basic + visibility: '$authType = "Basic"' path: basic widget: FormGroup children: @@ -727,6 +796,67 @@ form: | children: - path: key enum: $keys($secret.data) + - name: OAuth2 + visibility: '$authType = "OAuth2"' + path: oauth2 + widget: FormGroup + children: + - name: Token URL + path: tokenURL + widget: FormGroup + children: + - name: Value + path: value + widget: Text + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + children: + - path: key + enum: $keys($secret.data) + - name: Client ID + path: clientID + widget: FormGroup + children: + - name: Value + path: value + widget: Text + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + children: + - path: key + enum: $keys($secret.data) + - name: Client Secret + path: clientSecret + widget: FormGroup + children: + - name: Value + path: value + widget: Text + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + children: + - path: key + enum: $keys($secret.data) + - name: Scopes + path: scopes + widget: SimpleList + children: + - path: '[]' + - name: Params + path: params + widget: KeyValuePair - name: Headers path: headers widget: GenericList @@ -868,10 +998,20 @@ dataSources: |- kind: Secret version: v1 filter: |- - $item.metadata.name = $root.spec.output.http.user.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.http.user.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.http.password.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.http.host.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.http.url.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.http.tls.ca.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.http.tls.cert.valueFrom.secretKeyRef.name or - $item.metadata.name = $root.spec.output.http.tls.key.valueFrom.secretKeyRef.name + $item.metadata.name = $root.spec.output.http.tls.key.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.endpoint.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.headers.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.tls.ca.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.tls.cert.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.tls.key.valueFrom.secretKeyRef.name diff --git a/helm/files/metricpipelines-busola-config.yaml b/helm/files/metricpipelines-busola-config.yaml index 8e2672efd9..0469273b82 100644 --- a/helm/files/metricpipelines-busola-config.yaml +++ b/helm/files/metricpipelines-busola-config.yaml @@ -233,35 +233,96 @@ details: |- widget: Panel visibility: $exists(spec.output.otlp.authentication) children: - - name: User + - name: Basic widget: Panel - visibility: $exists(spec.output.otlp.authentication.basic.user) + visibility: $exists(spec.output.otlp.authentication.basic) children: - - name: Value - source: spec.output.otlp.authentication.basic.user.value - visibility: $exists(spec.output.otlp.authentication.basic.user.value) - - name: Value From Secret - widget: ResourceRefs - source: >- - spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef - kind: Secret - visibility: >- - $exists(spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name) - - name: Password + - name: User + widget: Panel + visibility: $exists(spec.output.otlp.authentication.basic.user) + children: + - name: Value + source: spec.output.otlp.authentication.basic.user.value + visibility: $exists(spec.output.otlp.authentication.basic.user.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name) + - name: Password + widget: Panel + visibility: $exists(spec.output.otlp.authentication.basic.password) + children: + - name: Value + source: spec.output.otlp.authentication.basic.password.value + visibility: >- + $exists(spec.output.otlp.authentication.basic.password.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name) + - name: OAuth2 widget: Panel - visibility: $exists(spec.output.otlp.authentication.basic.password) + visibility: $exists(spec.output.otlp.authentication.oauth2) children: - - name: Value - source: spec.output.otlp.authentication.basic.password.value - visibility: >- - $exists(spec.output.otlp.authentication.basic.password.value) - - name: Value From Secret - widget: ResourceRefs - source: >- - spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef - kind: Secret - visibility: >- - $exists(spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name) + - name: Token URL + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.tokenURL) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.tokenURL.value + visibility: $exists(spec.output.otlp.authentication.oauth2.tokenURL.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef.name) + - name: Client ID + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.clientID) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.clientID.value + visibility: $exists(spec.output.otlp.authentication.oauth2.clientID.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef.name) + - name: Client Secret + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.clientSecret) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.clientSecret.value + visibility: $exists(spec.output.otlp.authentication.oauth2.clientSecret.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef.name) + - name: Scopes + widget: JoinedArray + source: spec.output.otlp.authentication.oauth2.scopes + separator: ', ' + visibility: $exists(spec.output.otlp.authentication.oauth2.scopes) + - name: Params + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.params) + children: + - name: Parameters + source: spec.output.otlp.authentication.oauth2.params - name: Headers widget: Panel visibility: $exists(spec.output.otlp.headers) @@ -562,46 +623,135 @@ form: | widget: FormGroup simple: true children: - - name: User - path: basic.user + - var: authType + type: string + simple: true + defaultValue: "Basic" + name: Authentication Type + enum: [Basic, OAuth2] + description: Authentication Type defines which authentication method to use for the OTLP endpoint. + - name: Basic + visibility: '$authType = "Basic"' + path: basic widget: FormGroup simple: true children: - - name: Value - path: value - widget: Text + - name: User + path: user + widget: FormGroup simple: true - - name: Secret Reference - path: valueFrom.secretKeyRef - widget: ResourceRef - resource: - kind: secret - version: v1 + children: + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: Password + path: password + widget: FormGroup simple: true children: - - simple: true - path: key - enum: $keys($secret.data) - - name: Password - path: basic.password + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: OAuth2 + visibility: '$authType = "OAuth2"' + path: oauth2 widget: FormGroup simple: true children: - - name: Value - path: value - widget: Text + - name: Token URL + path: tokenURL + widget: FormGroup simple: true - - name: Secret Reference - path: valueFrom.secretKeyRef - widget: ResourceRef - resource: - kind: secret - version: v1 + children: + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: Client ID + path: clientID + widget: FormGroup simple: true children: - - simple: true - path: key - enum: $keys($secret.data) + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: Client Secret + path: clientSecret + widget: FormGroup + simple: true + children: + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: Scopes + path: scopes + widget: SimpleList + simple: true + children: + - path: '[]' + - name: Params + path: params + widget: KeyValuePair + simple: true - name: Headers path: headers[] widget: FormGroup @@ -747,8 +897,11 @@ dataSources: |- kind: Secret version: v1 filter: |- - $item.metadata.name = $root.spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name or - $item.metadata.name = $root.spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.otlp.endpoint.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.otlp.headers.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.otlp.tls.ca.valueFrom.secretKeyRef.name or diff --git a/helm/files/tracepipelines-busola-config.yaml b/helm/files/tracepipelines-busola-config.yaml index ab820fd7f8..4078f67a11 100644 --- a/helm/files/tracepipelines-busola-config.yaml +++ b/helm/files/tracepipelines-busola-config.yaml @@ -110,35 +110,96 @@ details: |- widget: Panel visibility: $exists(spec.output.otlp.authentication) children: - - name: User + - name: Basic widget: Panel - visibility: $exists(spec.output.otlp.authentication.basic.user) + visibility: $exists(spec.output.otlp.authentication.basic) children: - - name: Value - source: spec.output.otlp.authentication.basic.user.value - visibility: $exists(spec.output.otlp.authentication.basic.user.value) - - name: Value From Secret - widget: ResourceRefs - source: >- - spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef - kind: Secret - visibility: >- - $exists(spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name) - - name: Password + - name: User + widget: Panel + visibility: $exists(spec.output.otlp.authentication.basic.user) + children: + - name: Value + source: spec.output.otlp.authentication.basic.user.value + visibility: $exists(spec.output.otlp.authentication.basic.user.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name) + - name: Password + widget: Panel + visibility: $exists(spec.output.otlp.authentication.basic.password) + children: + - name: Value + source: spec.output.otlp.authentication.basic.password.value + visibility: >- + $exists(spec.output.otlp.authentication.basic.password.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name) + - name: OAuth2 widget: Panel - visibility: $exists(spec.output.otlp.authentication.basic.password) + visibility: $exists(spec.output.otlp.authentication.oauth2) children: - - name: Value - source: spec.output.otlp.authentication.basic.password.value - visibility: >- - $exists(spec.output.otlp.authentication.basic.password.value) - - name: Value From Secret - widget: ResourceRefs - source: >- - spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef - kind: Secret - visibility: >- - $exists(spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name) + - name: Token URL + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.tokenURL) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.tokenURL.value + visibility: $exists(spec.output.otlp.authentication.oauth2.tokenURL.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef.name) + - name: Client ID + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.clientID) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.clientID.value + visibility: $exists(spec.output.otlp.authentication.oauth2.clientID.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef.name) + - name: Client Secret + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.clientSecret) + children: + - name: Value + source: spec.output.otlp.authentication.oauth2.clientSecret.value + visibility: $exists(spec.output.otlp.authentication.oauth2.clientSecret.value) + - name: Value From Secret + widget: ResourceRefs + source: >- + spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef + kind: Secret + visibility: >- + $exists(spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef.name) + - name: Scopes + widget: JoinedArray + source: spec.output.otlp.authentication.oauth2.scopes + separator: ', ' + visibility: $exists(spec.output.otlp.authentication.oauth2.scopes) + - name: Params + widget: Panel + visibility: $exists(spec.output.otlp.authentication.oauth2.params) + children: + - name: Parameters + source: spec.output.otlp.authentication.oauth2.params - name: Headers widget: Panel visibility: $exists(spec.output.otlp.headers) @@ -284,46 +345,135 @@ form: | widget: FormGroup simple: true children: - - name: User - path: basic.user + - var: authType + type: string + simple: true + defaultValue: "Basic" + name: Authentication Type + enum: [Basic, OAuth2] + description: Authentication Type defines which authentication method to use for the OTLP endpoint. + - name: Basic + visibility: '$authType = "Basic"' + path: basic widget: FormGroup simple: true children: - - name: Value - path: value - widget: Text + - name: User + path: user + widget: FormGroup simple: true - - name: Secret Reference - path: valueFrom.secretKeyRef - widget: ResourceRef - resource: - kind: secret - version: v1 + children: + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: Password + path: password + widget: FormGroup simple: true children: - - simple: true - path: key - enum: $keys($secret.data) - - name: Password - path: basic.password + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: OAuth2 + visibility: '$authType = "OAuth2"' + path: oauth2 widget: FormGroup simple: true children: - - name: Value - path: value - widget: Text + - name: Token URL + path: tokenURL + widget: FormGroup simple: true - - name: Secret Reference - path: valueFrom.secretKeyRef - widget: ResourceRef - resource: - kind: secret - version: v1 + children: + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: Client ID + path: clientID + widget: FormGroup simple: true children: - - simple: true - path: key - enum: $keys($secret.data) + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: Client Secret + path: clientSecret + widget: FormGroup + simple: true + children: + - name: Value + path: value + widget: Text + simple: true + - name: Secret Reference + path: valueFrom.secretKeyRef + widget: ResourceRef + resource: + kind: secret + version: v1 + simple: true + children: + - simple: true + path: key + enum: $keys($secret.data) + - name: Scopes + path: scopes + widget: SimpleList + simple: true + children: + - path: '[]' + - name: Params + path: params + widget: KeyValuePair + simple: true - name: Headers path: headers[] widget: FormGroup @@ -469,8 +619,11 @@ dataSources: |- kind: Secret version: v1 filter: |- - $item.metadata.name = $root.spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name or - $item.metadata.name = $root.spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.tokenURL.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.clientID.valueFrom.secretKeyRef.name or + $item.metadata.name = $root.spec.output.otlp.authentication.oauth2.clientSecret.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.otlp.endpoint.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.otlp.headers.valueFrom.secretKeyRef.name or $item.metadata.name = $root.spec.output.otlp.tls.ca.valueFrom.secretKeyRef.name or diff --git a/internal/otelcollector/config/common/component_builder.go b/internal/otelcollector/config/common/component_builder.go index 0923733808..74d57bd032 100644 --- a/internal/otelcollector/config/common/component_builder.go +++ b/internal/otelcollector/config/common/component_builder.go @@ -194,11 +194,15 @@ func (cb *ComponentBuilder[T]) AddExporter(componentIDFunc ComponentIDFunc[T], c } } -func (cb *ComponentBuilder[T]) AddExtension(componentID string, extensionConfig any) { +func (cb *ComponentBuilder[T]) AddExtension(componentID string, extensionConfig any, extensionEnvVars EnvVars) { if _, found := cb.Config.Extensions[componentID]; !found { cb.Config.Extensions[componentID] = extensionConfig } + if extensionEnvVars != nil { + maps.Copy(cb.EnvVars, extensionEnvVars) + } + // Ensure the extension is added to the service only once extensions := cb.Config.Service.Extensions if slices.Contains(extensions, componentID) { diff --git a/internal/otelcollector/config/common/constants.go b/internal/otelcollector/config/common/constants.go index 7ec5ff946a..aa6aa3dffb 100644 --- a/internal/otelcollector/config/common/constants.go +++ b/internal/otelcollector/config/common/constants.go @@ -186,4 +186,5 @@ const ( ComponentIDFileStorageExtension = "file_storage" ComponentIDHealthCheckExtension = "health_check" ComponentIDPprofExtension = "pprof" + ComponentIDOAuth2Extension = "oauth2client/%s" // dynamically filled with pipeline name ) diff --git a/internal/otelcollector/config/common/env_vars.go b/internal/otelcollector/config/common/env_vars.go new file mode 100644 index 0000000000..044758316f --- /dev/null +++ b/internal/otelcollector/config/common/env_vars.go @@ -0,0 +1,263 @@ +package common + +import ( + "bytes" + "context" + "encoding/base64" + "fmt" + "net/url" + "path" + "strings" + + "sigs.k8s.io/controller-runtime/pkg/client" + + telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + sharedtypesutils "github.com/kyma-project/telemetry-manager/internal/utils/sharedtypes" +) + +const ( + basicAuthHeaderVariablePrefix = "BASIC_AUTH_HEADER" + otlpEndpointVariablePrefix = "OTLP_ENDPOINT" + tlsConfigCertVariablePrefix = "OTLP_TLS_CERT_PEM" + tlsConfigKeyVariablePrefix = "OTLP_TLS_KEY_PEM" + tlsConfigCaVariablePrefix = "OTLP_TLS_CA_PEM" + oauth2TokenURLVariablePrefix = "OAUTH2_TOKEN_URL" //nolint:gosec // G101: This is a variable name prefix, not a credential + oauth2ClientIDVariablePrefix = "OAUTH2_CLIENT_ID" //nolint:gosec // G101: This is a variable name prefix, not a credential + oauth2ClientSecretVariablePrefix = "OAUTH2_CLIENT_SECRET" //nolint:gosec // G101: This is a variable name prefix, not a credential +) + +// ============================================================================= +// Env Vars Builders +// ============================================================================= + +func makeOTLPExporterEnvVars(ctx context.Context, c client.Reader, output *telemetryv1alpha1.OTLPOutput, pipelineName string) (map[string][]byte, error) { + var err error + + secretData := make(map[string][]byte) + + err = makeBasicAuthEnvVar(ctx, c, secretData, output, pipelineName) + if err != nil { + return nil, err + } + + err = makeOTLPEndpointEnvVar(ctx, c, secretData, output, pipelineName) + if err != nil { + return nil, err + } + + err = makeHeaderEnvVar(ctx, c, secretData, output, pipelineName) + if err != nil { + return nil, err + } + + err = makeTLSEnvVar(ctx, c, secretData, output, pipelineName) + if err != nil { + return nil, err + } + + return secretData, nil +} + +func makeOAuth2ExtensionEnvVars(ctx context.Context, c client.Reader, oauth2Options *telemetryv1alpha1.OAuth2Options, pipelineName string) (map[string][]byte, error) { + var err error + + secretData := make(map[string][]byte) + + err = makeTokenURLEnvVar(ctx, c, secretData, oauth2Options, pipelineName) + if err != nil { + return nil, err + } + + err = makeClientIDEnvVar(ctx, c, secretData, oauth2Options, pipelineName) + if err != nil { + return nil, err + } + + err = makeClientSecretEnvVar(ctx, c, secretData, oauth2Options, pipelineName) + if err != nil { + return nil, err + } + + return secretData, nil +} + +func makeBasicAuthEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, output *telemetryv1alpha1.OTLPOutput, pipelineName string) error { + if isBasicAuthEnabled(output.Authentication) { + username, err := sharedtypesutils.ResolveValue(ctx, c, output.Authentication.Basic.User) + if err != nil { + return err + } + + password, err := sharedtypesutils.ResolveValue(ctx, c, output.Authentication.Basic.Password) + if err != nil { + return err + } + + basicAuthHeader := formatBasicAuthHeader(string(username), string(password)) + basicAuthHeaderVariable := formatEnvVarKey(basicAuthHeaderVariablePrefix, sanitizeEnvVarName(pipelineName)) + secretData[basicAuthHeaderVariable] = []byte(basicAuthHeader) + } + + return nil +} + +func makeOTLPEndpointEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, output *telemetryv1alpha1.OTLPOutput, pipelineName string) error { + otlpEndpointVariable := formatEnvVarKey(otlpEndpointVariablePrefix, pipelineName) + + endpointURL, err := resolveEndpointURL(ctx, c, output) + if err != nil { + return err + } + + secretData[otlpEndpointVariable] = endpointURL + + return err +} + +func makeHeaderEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, output *telemetryv1alpha1.OTLPOutput, pipelineName string) error { + for _, header := range output.Headers { + key := formatHeaderEnvVarKey(header, pipelineName) + + value, err := sharedtypesutils.ResolveValue(ctx, c, header.ValueType) + if err != nil { + return err + } + + secretData[key] = prefixHeaderValue(header, value) + } + + return nil +} + +func makeTLSEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, output *telemetryv1alpha1.OTLPOutput, pipelineName string) error { + if output.TLS != nil { + if sharedtypesutils.IsValid(output.TLS.CA) { + ca, err := sharedtypesutils.ResolveValue(ctx, c, *output.TLS.CA) + if err != nil { + return err + } + + tlsConfigCaVariable := formatEnvVarKey(tlsConfigCaVariablePrefix, pipelineName) + secretData[tlsConfigCaVariable] = ca + } + + if sharedtypesutils.IsValid(output.TLS.Cert) && sharedtypesutils.IsValid(output.TLS.Key) { + cert, err := sharedtypesutils.ResolveValue(ctx, c, *output.TLS.Cert) + if err != nil { + return err + } + + key, err := sharedtypesutils.ResolveValue(ctx, c, *output.TLS.Key) + if err != nil { + return err + } + + // Make a best effort replacement of linebreaks in cert/key if present. + sanitizedCert := bytes.ReplaceAll(cert, []byte("\\n"), []byte("\n")) + sanitizedKey := bytes.ReplaceAll(key, []byte("\\n"), []byte("\n")) + + tlsConfigCertVariable := formatEnvVarKey(tlsConfigCertVariablePrefix, pipelineName) + secretData[tlsConfigCertVariable] = sanitizedCert + + tlsConfigKeyVariable := formatEnvVarKey(tlsConfigKeyVariablePrefix, pipelineName) + secretData[tlsConfigKeyVariable] = sanitizedKey + } + } + + return nil +} + +func makeTokenURLEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, oauth2Options *telemetryv1alpha1.OAuth2Options, pipelineName string) error { + if oauth2Options != nil && sharedtypesutils.IsValid(&oauth2Options.TokenURL) { + tokenURL, err := sharedtypesutils.ResolveValue(ctx, c, oauth2Options.TokenURL) + if err != nil { + return err + } + + tokenURLVariable := formatEnvVarKey(oauth2TokenURLVariablePrefix, sanitizeEnvVarName(pipelineName)) + secretData[tokenURLVariable] = tokenURL + } + + return nil +} + +func makeClientIDEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, oauth2Options *telemetryv1alpha1.OAuth2Options, pipelineName string) error { + if oauth2Options != nil && sharedtypesutils.IsValid(&oauth2Options.ClientID) { + clientID, err := sharedtypesutils.ResolveValue(ctx, c, oauth2Options.ClientID) + if err != nil { + return err + } + + clientIDVariable := formatEnvVarKey(oauth2ClientIDVariablePrefix, sanitizeEnvVarName(pipelineName)) + secretData[clientIDVariable] = clientID + } + + return nil +} + +func makeClientSecretEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, oauth2Options *telemetryv1alpha1.OAuth2Options, pipelineName string) error { + if oauth2Options != nil && sharedtypesutils.IsValid(&oauth2Options.ClientSecret) { + clientSecret, err := sharedtypesutils.ResolveValue(ctx, c, oauth2Options.ClientSecret) + if err != nil { + return err + } + + clientSecretVariable := formatEnvVarKey(oauth2ClientSecretVariablePrefix, sanitizeEnvVarName(pipelineName)) + secretData[clientSecretVariable] = clientSecret + } + + return nil +} + +// ============================================================================= +// Helper Functions +// ============================================================================= + +func prefixHeaderValue(header telemetryv1alpha1.Header, value []byte) []byte { + if len(strings.TrimSpace(header.Prefix)) > 0 { + return fmt.Appendf(nil, "%s %s", strings.TrimSpace(header.Prefix), string(value)) + } + + return value +} + +func resolveEndpointURL(ctx context.Context, c client.Reader, output *telemetryv1alpha1.OTLPOutput) ([]byte, error) { + endpoint, err := sharedtypesutils.ResolveValue(ctx, c, output.Endpoint) + if err != nil { + return nil, err + } + + if len(output.Path) > 0 { + u, err := url.Parse(string(endpoint)) + if err != nil { + return nil, err + } + + u.Path = path.Join(u.Path, output.Path) + + return []byte(u.String()), nil + } + + return endpoint, nil +} + +func formatBasicAuthHeader(username string, password string) string { + return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(username+":"+password))) +} + +func formatEnvVarKey(prefix string, pipelineName string) string { + return fmt.Sprintf("%s_%s", prefix, sanitizeEnvVarName(pipelineName)) +} + +func formatHeaderEnvVarKey(header telemetryv1alpha1.Header, pipelineName string) string { + return fmt.Sprintf("HEADER_%s_%s", sanitizeEnvVarName(pipelineName), sanitizeEnvVarName(header.Name)) +} + +func sanitizeEnvVarName(input string) string { + result := input + result = strings.ToUpper(result) + result = strings.ReplaceAll(result, ".", "_") + result = strings.ReplaceAll(result, "-", "_") + + return result +} diff --git a/internal/otelcollector/config/common/oauth2extension_config_builder.go b/internal/otelcollector/config/common/oauth2extension_config_builder.go new file mode 100644 index 0000000000..4a1916a91c --- /dev/null +++ b/internal/otelcollector/config/common/oauth2extension_config_builder.go @@ -0,0 +1,55 @@ +package common + +import ( + "context" + "fmt" + + "sigs.k8s.io/controller-runtime/pkg/client" + + telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" +) + +// ============================================================================= +// OAuth2 EXTENSION CONFIG BUILDER +// ============================================================================= + +type OAuth2ExtensionConfigBuilder struct { + reader client.Reader + oauth2Options *telemetryv1alpha1.OAuth2Options + pipelineName string + signalType string +} + +func NewOAuth2ExtensionConfigBuilder(reader client.Reader, oauth2Options *telemetryv1alpha1.OAuth2Options, pipelineName string, signalType string) *OAuth2ExtensionConfigBuilder { + return &OAuth2ExtensionConfigBuilder{ + reader: reader, + oauth2Options: oauth2Options, + pipelineName: pipelineName, + signalType: signalType, + } +} + +func (cb *OAuth2ExtensionConfigBuilder) OAuth2ExtensionConfig(ctx context.Context) (*OAuth2Extension, EnvVars, error) { + envVars, err := makeOAuth2ExtensionEnvVars(ctx, cb.reader, cb.oauth2Options, cb.pipelineName) + if err != nil { + return nil, nil, fmt.Errorf("failed to make env vars: %w", err) + } + + extensionsConfig := makeExtensionConfig(cb.oauth2Options, cb.pipelineName) + + return extensionsConfig, envVars, nil +} + +func makeExtensionConfig(oauth2Options *telemetryv1alpha1.OAuth2Options, pipelineName string) *OAuth2Extension { + return &OAuth2Extension{ + TokenURL: fmt.Sprintf("${%s}", formatEnvVarKey(oauth2TokenURLVariablePrefix, pipelineName)), + ClientID: fmt.Sprintf("${%s}", formatEnvVarKey(oauth2ClientIDVariablePrefix, pipelineName)), + ClientSecret: fmt.Sprintf("${%s}", formatEnvVarKey(oauth2ClientSecretVariablePrefix, pipelineName)), + Scopes: oauth2Options.Scopes, + Params: oauth2Options.Params, + } +} + +func OAuth2ExtensionID(pipelineName string) string { + return fmt.Sprintf(ComponentIDOAuth2Extension, pipelineName) +} diff --git a/internal/otelcollector/config/common/oauth2extension_config_builder_test.go b/internal/otelcollector/config/common/oauth2extension_config_builder_test.go new file mode 100644 index 0000000000..dfba69f730 --- /dev/null +++ b/internal/otelcollector/config/common/oauth2extension_config_builder_test.go @@ -0,0 +1,40 @@ +package common + +import ( + "testing" + + "github.com/stretchr/testify/require" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" +) + +func TestOAuth2ExtensionID(t *testing.T) { + require.Equal(t, "oauth2client/test", OAuth2ExtensionID("test")) +} + +func TestMakeExtensionConfig(t *testing.T) { + oauth2Options := &telemetryv1alpha1.OAuth2Options{ + TokenURL: telemetryv1alpha1.ValueType{Value: "token-url"}, + ClientID: telemetryv1alpha1.ValueType{Value: "client-id"}, + ClientSecret: telemetryv1alpha1.ValueType{Value: "client-secret"}, + } + + cb := NewOAuth2ExtensionConfigBuilder(fake.NewClientBuilder().Build(), oauth2Options, "test", SignalTypeTrace) + oauth2ExtensionConfig, envVars, err := cb.OAuth2ExtensionConfig(t.Context()) + require.NoError(t, err) + require.NotNil(t, envVars) + + require.NotNil(t, envVars["OAUTH2_TOKEN_URL_TEST"]) + require.Equal(t, envVars["OAUTH2_TOKEN_URL_TEST"], []byte("token-url")) + + require.NotNil(t, envVars["OAUTH2_CLIENT_ID_TEST"]) + require.Equal(t, envVars["OAUTH2_CLIENT_ID_TEST"], []byte("client-id")) + + require.NotNil(t, envVars["OAUTH2_CLIENT_SECRET_TEST"]) + require.Equal(t, envVars["OAUTH2_CLIENT_SECRET_TEST"], []byte("client-secret")) + + require.Equal(t, "${OAUTH2_TOKEN_URL_TEST}", oauth2ExtensionConfig.TokenURL) + require.Equal(t, "${OAUTH2_CLIENT_ID_TEST}", oauth2ExtensionConfig.ClientID) + require.Equal(t, "${OAUTH2_CLIENT_SECRET_TEST}", oauth2ExtensionConfig.ClientSecret) +} diff --git a/internal/otelcollector/config/common/otlpexporter_config_builder.go b/internal/otelcollector/config/common/otlpexporter_config_builder.go index 91c826d62b..4899908b24 100644 --- a/internal/otelcollector/config/common/otlpexporter_config_builder.go +++ b/internal/otelcollector/config/common/otlpexporter_config_builder.go @@ -36,19 +36,19 @@ func NewOTLPExporterConfigBuilder(reader client.Reader, otlpOutput *telemetryv1a } func (cb *OTLPExporterConfigBuilder) OTLPExporterConfig(ctx context.Context) (*OTLPExporter, EnvVars, error) { - envVars, err := makeEnvVars(ctx, cb.reader, cb.otlpOutput, cb.pipelineName) + envVars, err := makeOTLPExporterEnvVars(ctx, cb.reader, cb.otlpOutput, cb.pipelineName) if err != nil { return nil, nil, fmt.Errorf("failed to make env vars: %w", err) } - exportersConfig := makeExportersConfig(cb.otlpOutput, cb.pipelineName, envVars, cb.queueSize, cb.signalType) + exportersConfig := makeExporterConfig(cb.otlpOutput, cb.pipelineName, envVars, cb.queueSize, cb.signalType) return exportersConfig, envVars, nil } -func makeExportersConfig(otlpOutput *telemetryv1alpha1.OTLPOutput, pipelineName string, envVars map[string][]byte, queueSize int, signalType string) *OTLPExporter { +func makeExporterConfig(otlpOutput *telemetryv1alpha1.OTLPOutput, pipelineName string, envVars map[string][]byte, queueSize int, signalType string) *OTLPExporter { headers := makeHeaders(otlpOutput, pipelineName) - otlpEndpointVariable := makeOTLPEndpointVariable(pipelineName) + otlpEndpointVariable := formatEnvVarKey(otlpEndpointVariablePrefix, pipelineName) otlpEndpointValue := string(envVars[otlpEndpointVariable]) tlsConfig := makeTLSConfig(otlpOutput, otlpEndpointValue, pipelineName) @@ -88,6 +88,12 @@ func makeExportersConfig(otlpOutput *telemetryv1alpha1.OTLPOutput, pipelineName otlpExporterConfig.LogsEndpoint = fmt.Sprintf("${%s}", otlpEndpointVariable) } + if otlpOutput.Authentication != nil && otlpOutput.Authentication.OAuth2 != nil { + otlpExporterConfig.Auth = Auth{ + Authenticator: fmt.Sprintf(ComponentIDOAuth2Extension, pipelineName), + } + } + return &otlpExporterConfig } @@ -114,15 +120,15 @@ func makeTLSConfig(output *telemetryv1alpha1.OTLPOutput, otlpEndpointValue, pipe cfg.InsecureSkipVerify = output.TLS.InsecureSkipVerify if sharedtypesutils.IsValid(output.TLS.CA) { - cfg.CAPem = fmt.Sprintf("${%s}", makeTLSCaVariable(pipelineName)) + cfg.CAPem = fmt.Sprintf("${%s}", formatEnvVarKey(tlsConfigCaVariablePrefix, pipelineName)) } if sharedtypesutils.IsValid(output.TLS.Cert) { - cfg.CertPem = fmt.Sprintf("${%s}", makeTLSCertVariable(pipelineName)) + cfg.CertPem = fmt.Sprintf("${%s}", formatEnvVarKey(tlsConfigCertVariablePrefix, pipelineName)) } if sharedtypesutils.IsValid(output.TLS.Key) { - cfg.KeyPem = fmt.Sprintf("${%s}", makeTLSKeyVariable(pipelineName)) + cfg.KeyPem = fmt.Sprintf("${%s}", formatEnvVarKey(tlsConfigKeyVariablePrefix, pipelineName)) } return cfg @@ -131,13 +137,13 @@ func makeTLSConfig(output *telemetryv1alpha1.OTLPOutput, otlpEndpointValue, pipe func makeHeaders(output *telemetryv1alpha1.OTLPOutput, pipelineName string) map[string]string { headers := make(map[string]string) - if output.Authentication != nil && sharedtypesutils.IsValid(&output.Authentication.Basic.User) && sharedtypesutils.IsValid(&output.Authentication.Basic.Password) { - basicAuthHeaderVariable := makeBasicAuthHeaderVariable(pipelineName) + if isBasicAuthEnabled(output.Authentication) { + basicAuthHeaderVariable := formatEnvVarKey(basicAuthHeaderVariablePrefix, pipelineName) headers["Authorization"] = fmt.Sprintf("${%s}", basicAuthHeaderVariable) } for _, header := range output.Headers { - headers[header.Name] = fmt.Sprintf("${%s}", makeHeaderVariable(header, pipelineName)) + headers[header.Name] = fmt.Sprintf("${%s}", formatHeaderEnvVarKey(header, pipelineName)) } return headers @@ -146,3 +152,10 @@ func makeHeaders(output *telemetryv1alpha1.OTLPOutput, pipelineName string) map[ func isInsecureOutput(endpoint string) bool { return len(strings.TrimSpace(endpoint)) > 0 && strings.HasPrefix(endpoint, "http://") } + +func isBasicAuthEnabled(authOptions *telemetryv1alpha1.AuthenticationOptions) bool { + return authOptions != nil && + authOptions.Basic != nil && + sharedtypesutils.IsValid(&authOptions.Basic.User) && + sharedtypesutils.IsValid(&authOptions.Basic.Password) +} diff --git a/internal/otelcollector/config/common/otlpexporter_config_builder_test.go b/internal/otelcollector/config/common/otlpexporter_config_builder_test.go index 6b78d4e5a7..b2f5a3e9f7 100644 --- a/internal/otelcollector/config/common/otlpexporter_config_builder_test.go +++ b/internal/otelcollector/config/common/otlpexporter_config_builder_test.go @@ -22,7 +22,7 @@ func TestExorterIDDefault(t *testing.T) { require.Equal(t, "otlp/test", ExporterID("", "test")) } -func TestMakeConfig(t *testing.T) { +func TestMakeExporterConfig(t *testing.T) { output := &telemetryv1alpha1.OTLPOutput{ Endpoint: telemetryv1alpha1.ValueType{Value: "otlp-endpoint"}, } @@ -45,7 +45,7 @@ func TestMakeConfig(t *testing.T) { require.Equal(t, "300s", otlpExporterConfig.RetryOnFailure.MaxElapsedTime) } -func TestMakeConfigTraceWithPath(t *testing.T) { +func TestMakeExporterConfigTraceWithPath(t *testing.T) { output := &telemetryv1alpha1.OTLPOutput{ Endpoint: telemetryv1alpha1.ValueType{Value: "otlp-endpoint"}, Path: "/v1/test", @@ -64,7 +64,7 @@ func TestMakeConfigTraceWithPath(t *testing.T) { require.Empty(t, otlpExporterConfig.Endpoint) } -func TestMakeConfigMetricWithPath(t *testing.T) { +func TestMakeExporterConfigMetricWithPath(t *testing.T) { output := &telemetryv1alpha1.OTLPOutput{ Endpoint: telemetryv1alpha1.ValueType{Value: "otlp-endpoint"}, Path: "/v1/test", @@ -83,7 +83,7 @@ func TestMakeConfigMetricWithPath(t *testing.T) { require.Empty(t, otlpExporterConfig.Endpoint) } -func TestMakeExporterWithBasicAuth(t *testing.T) { +func TestMakeExporterConfigWithBasicAuth(t *testing.T) { output := &telemetryv1alpha1.OTLPOutput{ Endpoint: telemetryv1alpha1.ValueType{Value: "otlp-endpoint"}, Authentication: &telemetryv1alpha1.AuthenticationOptions{ @@ -108,6 +108,27 @@ func TestMakeExporterWithBasicAuth(t *testing.T) { require.Equal(t, envVars["BASIC_AUTH_HEADER_TEST"], []byte("Basic "+base64UserPass)) } +func TestMakeExporterConfigWithOAuth2(t *testing.T) { + output := &telemetryv1alpha1.OTLPOutput{ + Endpoint: telemetryv1alpha1.ValueType{Value: "otlp-endpoint"}, + Authentication: &telemetryv1alpha1.AuthenticationOptions{ + OAuth2: &telemetryv1alpha1.OAuth2Options{ + TokenURL: telemetryv1alpha1.ValueType{Value: "token-url"}, + ClientID: telemetryv1alpha1.ValueType{Value: "client-id"}, + ClientSecret: telemetryv1alpha1.ValueType{Value: "client-secret"}, + }, + }, + } + + cb := NewOTLPExporterConfigBuilder(fake.NewClientBuilder().Build(), output, "test", 512, SignalTypeTrace) + otlpExporterConfig, envVars, err := cb.OTLPExporterConfig(t.Context()) + require.NoError(t, err) + require.NotNil(t, envVars) + + require.NotNil(t, otlpExporterConfig.Auth) + require.Equal(t, otlpExporterConfig.Auth.Authenticator, "oauth2client/test") +} + func TestMakeExporterConfigWithCustomHeaders(t *testing.T) { headers := []telemetryv1alpha1.Header{ { diff --git a/internal/otelcollector/config/common/otlpexporter_env_vars.go b/internal/otelcollector/config/common/otlpexporter_env_vars.go deleted file mode 100644 index abb068855c..0000000000 --- a/internal/otelcollector/config/common/otlpexporter_env_vars.go +++ /dev/null @@ -1,221 +0,0 @@ -package common - -import ( - "bytes" - "context" - "encoding/base64" - "errors" - "fmt" - "net/url" - "path" - "strings" - - "sigs.k8s.io/controller-runtime/pkg/client" - - telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" - sharedtypesutils "github.com/kyma-project/telemetry-manager/internal/utils/sharedtypes" - "github.com/kyma-project/telemetry-manager/internal/validators/secretref" -) - -const ( - basicAuthHeaderVariablePrefix = "BASIC_AUTH_HEADER" - otlpEndpointVariablePrefix = "OTLP_ENDPOINT" - tlsConfigCertVariablePrefix = "OTLP_TLS_CERT_PEM" - tlsConfigKeyVariablePrefix = "OTLP_TLS_KEY_PEM" - tlsConfigCaVariablePrefix = "OTLP_TLS_CA_PEM" -) - -var ( - ErrValueOrSecretRefUndefined = errors.New("either value or secret key reference must be defined") -) - -func makeEnvVars(ctx context.Context, c client.Reader, output *telemetryv1alpha1.OTLPOutput, pipelineName string) (map[string][]byte, error) { - var err error - - secretData := make(map[string][]byte) - - err = makeAuthenticationEnvVar(ctx, c, secretData, output, pipelineName) - if err != nil { - return nil, err - } - - err = makeOTLPEndpointEnvVar(ctx, c, secretData, output, pipelineName) - if err != nil { - return nil, err - } - - err = makeHeaderEnvVar(ctx, c, secretData, output, pipelineName) - if err != nil { - return nil, err - } - - err = makeTLSEnvVar(ctx, c, secretData, output, pipelineName) - if err != nil { - return nil, err - } - - return secretData, nil -} - -func makeAuthenticationEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, output *telemetryv1alpha1.OTLPOutput, pipelineName string) error { - if output.Authentication != nil && sharedtypesutils.IsValid(&output.Authentication.Basic.User) && sharedtypesutils.IsValid(&output.Authentication.Basic.Password) { - username, err := ResolveValue(ctx, c, output.Authentication.Basic.User) - if err != nil { - return err - } - - password, err := ResolveValue(ctx, c, output.Authentication.Basic.Password) - if err != nil { - return err - } - - basicAuthHeader := formatBasicAuthHeader(string(username), string(password)) - basicAuthHeaderVariable := fmt.Sprintf("%s_%s", basicAuthHeaderVariablePrefix, sanitizeEnvVarName(pipelineName)) - secretData[basicAuthHeaderVariable] = []byte(basicAuthHeader) - } - - return nil -} - -func makeOTLPEndpointEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, output *telemetryv1alpha1.OTLPOutput, pipelineName string) error { - otlpEndpointVariable := makeOTLPEndpointVariable(pipelineName) - - endpointURL, err := resolveEndpointURL(ctx, c, output) - if err != nil { - return err - } - - secretData[otlpEndpointVariable] = endpointURL - - return err -} - -func makeHeaderEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, output *telemetryv1alpha1.OTLPOutput, pipelineName string) error { - for _, header := range output.Headers { - key := makeHeaderVariable(header, pipelineName) - - value, err := ResolveValue(ctx, c, header.ValueType) - if err != nil { - return err - } - - secretData[key] = prefixHeaderValue(header, value) - } - - return nil -} - -func makeTLSEnvVar(ctx context.Context, c client.Reader, secretData map[string][]byte, output *telemetryv1alpha1.OTLPOutput, pipelineName string) error { - if output.TLS != nil { - if sharedtypesutils.IsValid(output.TLS.CA) { - ca, err := ResolveValue(ctx, c, *output.TLS.CA) - if err != nil { - return err - } - - tlsConfigCaVariable := makeTLSCaVariable(pipelineName) - secretData[tlsConfigCaVariable] = ca - } - - if sharedtypesutils.IsValid(output.TLS.Cert) && sharedtypesutils.IsValid(output.TLS.Key) { - cert, err := ResolveValue(ctx, c, *output.TLS.Cert) - if err != nil { - return err - } - - key, err := ResolveValue(ctx, c, *output.TLS.Key) - if err != nil { - return err - } - - // Make a best effort replacement of linebreaks in cert/key if present. - sanitizedCert := bytes.ReplaceAll(cert, []byte("\\n"), []byte("\n")) - sanitizedKey := bytes.ReplaceAll(key, []byte("\\n"), []byte("\n")) - - tlsConfigCertVariable := makeTLSCertVariable(pipelineName) - secretData[tlsConfigCertVariable] = sanitizedCert - - tlsConfigKeyVariable := makeTLSKeyVariable(pipelineName) - secretData[tlsConfigKeyVariable] = sanitizedKey - } - } - - return nil -} - -func prefixHeaderValue(header telemetryv1alpha1.Header, value []byte) []byte { - if len(strings.TrimSpace(header.Prefix)) > 0 { - return fmt.Appendf(nil, "%s %s", strings.TrimSpace(header.Prefix), string(value)) - } - - return value -} - -func resolveEndpointURL(ctx context.Context, c client.Reader, output *telemetryv1alpha1.OTLPOutput) ([]byte, error) { - endpoint, err := ResolveValue(ctx, c, output.Endpoint) - if err != nil { - return nil, err - } - - if len(output.Path) > 0 { - u, err := url.Parse(string(endpoint)) - if err != nil { - return nil, err - } - - u.Path = path.Join(u.Path, output.Path) - - return []byte(u.String()), nil - } - - return endpoint, nil -} - -func formatBasicAuthHeader(username string, password string) string { - return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(username+":"+password))) -} - -func ResolveValue(ctx context.Context, c client.Reader, value telemetryv1alpha1.ValueType) ([]byte, error) { - if value.Value != "" { - return []byte(value.Value), nil - } - - if value.ValueFrom.SecretKeyRef != nil { - return secretref.GetValue(ctx, c, *value.ValueFrom.SecretKeyRef) - } - - return nil, ErrValueOrSecretRefUndefined -} - -func makeOTLPEndpointVariable(pipelineName string) string { - return fmt.Sprintf("%s_%s", otlpEndpointVariablePrefix, sanitizeEnvVarName(pipelineName)) -} - -func makeBasicAuthHeaderVariable(pipelineName string) string { - return fmt.Sprintf("%s_%s", basicAuthHeaderVariablePrefix, sanitizeEnvVarName(pipelineName)) -} - -func makeHeaderVariable(header telemetryv1alpha1.Header, pipelineName string) string { - return fmt.Sprintf("HEADER_%s_%s", sanitizeEnvVarName(pipelineName), sanitizeEnvVarName(header.Name)) -} - -func makeTLSCertVariable(pipelineName string) string { - return fmt.Sprintf("%s_%s", tlsConfigCertVariablePrefix, sanitizeEnvVarName(pipelineName)) -} - -func makeTLSKeyVariable(pipelineName string) string { - return fmt.Sprintf("%s_%s", tlsConfigKeyVariablePrefix, sanitizeEnvVarName(pipelineName)) -} - -func makeTLSCaVariable(pipelineName string) string { - return fmt.Sprintf("%s_%s", tlsConfigCaVariablePrefix, sanitizeEnvVarName(pipelineName)) -} - -func sanitizeEnvVarName(input string) string { - result := input - result = strings.ToUpper(result) - result = strings.ReplaceAll(result, ".", "_") - result = strings.ReplaceAll(result, "-", "_") - - return result -} diff --git a/internal/otelcollector/config/common/types.go b/internal/otelcollector/config/common/types.go index 1facc025a9..d6d6ff2557 100644 --- a/internal/otelcollector/config/common/types.go +++ b/internal/otelcollector/config/common/types.go @@ -19,17 +19,25 @@ type Config struct { // EXTENSION TYPES // ============================================================================= -type K8sLeaderElector struct { +type K8sLeaderElectorExtension struct { AuthType string `yaml:"auth_type,omitempty"` LeaseName string `yaml:"lease_name,omitempty"` LeaseNamespace string `yaml:"lease_namespace,omitempty"` } -type FileStorage struct { +type FileStorageExtension struct { CreateDirectory bool `yaml:"create_directory,omitempty"` Directory string `yaml:"directory,omitempty"` } +type OAuth2Extension struct { + TokenURL string `yaml:"token_url"` + ClientID string `yaml:"client_id"` + ClientSecret string `yaml:"client_secret"` + Scopes []string `yaml:"scopes,omitempty"` + Params map[string]string `yaml:"endpoint_params,omitempty"` +} + // ============================================================================= // SERVICE TYPES // ============================================================================= @@ -107,6 +115,7 @@ type OTLPExporter struct { TLS TLS `yaml:"tls,omitempty"` SendingQueue SendingQueue `yaml:"sending_queue,omitempty"` RetryOnFailure RetryOnFailure `yaml:"retry_on_failure,omitempty"` + Auth Auth `yaml:"auth,omitempty"` } type TLS struct { @@ -129,6 +138,10 @@ type RetryOnFailure struct { MaxElapsedTime string `yaml:"max_elapsed_time"` } +type Auth struct { + Authenticator string `yaml:"authenticator"` +} + // ============================================================================= // PROCESSOR TYPES // ============================================================================= diff --git a/internal/otelcollector/config/logagent/config_builder.go b/internal/otelcollector/config/logagent/config_builder.go index 9f90654a47..2780680f08 100644 --- a/internal/otelcollector/config/logagent/config_builder.go +++ b/internal/otelcollector/config/logagent/config_builder.go @@ -33,14 +33,21 @@ type BuildOptions struct { func (b *Builder) Build(ctx context.Context, pipelines []telemetryv1alpha1.LogPipeline, opts BuildOptions) (*common.Config, common.EnvVars, error) { b.Config = common.NewConfig() - b.AddExtension(common.ComponentIDFileStorageExtension, &common.FileStorage{ + b.AddExtension(common.ComponentIDFileStorageExtension, &common.FileStorageExtension{ CreateDirectory: true, Directory: filepath.Join(otelcollector.CheckpointVolumePath, checkpointVolumePathSubdir), - }) + }, nil) b.EnvVars = make(common.EnvVars) for _, pipeline := range pipelines { pipelineID := formatLogServicePipelineID(&pipeline) + + if shouldEnableOAuth2(&pipeline) { + if err := b.addOAuth2Extension(ctx, &pipeline); err != nil { + return nil, nil, err + } + } + if err := b.AddServicePipeline(ctx, &pipeline, pipelineID, b.addFileLogReceiver(), b.addMemoryLimiterProcessor(), @@ -182,6 +189,28 @@ func (b *Builder) addOTLPExporter() buildComponentFunc { ) } +func (b *Builder) addOAuth2Extension(ctx context.Context, pipeline *telemetryv1alpha1.LogPipeline) error { + oauth2ExtensionID := common.OAuth2ExtensionID(pipeline.Name) + + oauth2ExtensionConfig, oauth2ExtensionEnvVars, err := common.NewOAuth2ExtensionConfigBuilder( + b.Reader, + pipeline.Spec.Output.OTLP.Authentication.OAuth2, + pipeline.Name, + common.SignalTypeTrace, + ).OAuth2ExtensionConfig(ctx) + if err != nil { + return fmt.Errorf("failed to build OAuth2 extension for pipeline %s: %w", pipeline.Name, err) + } + + b.AddExtension(oauth2ExtensionID, oauth2ExtensionConfig, oauth2ExtensionEnvVars) + + return nil +} + +func shouldEnableOAuth2(tp *telemetryv1alpha1.LogPipeline) bool { + return tp.Spec.Output.OTLP.Authentication != nil && tp.Spec.Output.OTLP.Authentication.OAuth2 != nil +} + func formatLogServicePipelineID(lp *telemetryv1alpha1.LogPipeline) string { return fmt.Sprintf("logs/%s", lp.Name) } diff --git a/internal/otelcollector/config/logagent/config_builder_test.go b/internal/otelcollector/config/logagent/config_builder_test.go index 76f44adb66..78f123d749 100644 --- a/internal/otelcollector/config/logagent/config_builder_test.go +++ b/internal/otelcollector/config/logagent/config_builder_test.go @@ -142,6 +142,24 @@ func TestBuildConfig(t *testing.T) { }, goldenFileName: "user-defined-transform-filter.yaml", }, + { + name: "pipeline using OAuth2 authentication", + pipelines: []telemetryv1alpha1.LogPipeline{ + testutils.NewLogPipelineBuilder(). + WithName("test"). + WithApplicationInput(true). + WithOTLPOutput( + testutils.OTLPProtocol("http"), + ). + WithOAuth2( + testutils.OAuth2ClientID("client-id"), + testutils.OAuth2ClientSecret("client-secret"), + testutils.OAuth2TokenURL("https://auth.example.com/oauth2/token"), + testutils.OAuth2Scopes([]string{"logs"}), + ).Build(), + }, + goldenFileName: "oauth2-authentication.yaml", + }, } buildOptions := BuildOptions{ diff --git a/internal/otelcollector/config/logagent/testdata/oauth2-authentication.yaml b/internal/otelcollector/config/logagent/testdata/oauth2-authentication.yaml new file mode 100644 index 0000000000..674fe1cc47 --- /dev/null +++ b/internal/otelcollector/config/logagent/testdata/oauth2-authentication.yaml @@ -0,0 +1,241 @@ +extensions: + file_storage: + create_directory: true + directory: /tmp/telemetry-log-agent/file-log-receiver + health_check: + endpoint: ${MY_POD_IP}:13133 + oauth2client/test: + token_url: ${OAUTH2_TOKEN_URL_TEST} + client_id: ${OAUTH2_CLIENT_ID_TEST} + client_secret: ${OAUTH2_CLIENT_SECRET_TEST} + scopes: + - logs + pprof: + endpoint: 127.0.0.1:1777 +service: + pipelines: + logs/test: + receivers: + - filelog/test + processors: + - memory_limiter + - transform/set-instrumentation-scope-runtime + - k8sattributes + - transform/insert-cluster-attributes + - service_enrichment + - transform/drop-kyma-attributes + exporters: + - otlphttp/test + telemetry: + metrics: + readers: + - pull: + exporter: + prometheus: + host: ${MY_POD_IP} + port: 8888 + logs: + level: info + encoding: json + extensions: + - health_check + - pprof + - file_storage + - oauth2client/test +receivers: + filelog/test: + exclude: + - /var/log/pods/kyma-system_telemetry-fluent-bit-*/fluent-bit/*.log + - /var/log/pods/kyma-system_telemetry-log-agent-*/collector/*.log + - /var/log/pods/kyma-system_*system-logs-agent-*/collector/*.log + - /var/log/pods/kyma-system_*system-logs-collector-*/collector/*.log + - /var/log/pods/kyma-system_*/*/*.log + - /var/log/pods/kube-system_*/*/*.log + - /var/log/pods/istio-system_*/*/*.log + include: + - /var/log/pods/*_*/*/*.log + include_file_name: false + include_file_path: true + start_at: beginning + storage: file_storage + retry_on_failure: + enabled: true + initial_interval: 5s + max_interval: 30s + max_elapsed_time: 300s + operators: + - id: containerd-parser + type: container + add_metadata_from_file_path: true + format: containerd + - id: move-to-log-stream + type: move + from: attributes["stream"] + to: attributes["log.iostream"] + if: attributes["stream"] != nil + - id: drop-attribute-log-tag + type: remove + field: attributes["logtag"] + - id: body-router + type: router + routes: + - expr: body matches '^{.*}$' + output: json-parser + default: noop + - id: json-parser + type: json_parser + parse_from: body + parse_to: attributes + - id: remove-body + type: remove + field: body + - id: move-message-to-body + type: move + from: attributes["message"] + to: body + if: attributes["message"] != nil + - id: move-msg-to-body + type: move + from: attributes["msg"] + to: body + if: attributes["msg"] != nil + - id: parse-level + type: severity_parser + if: attributes["level"] != nil + parse_from: attributes["level"] + - id: remove-level + type: remove + if: attributes["level"] != nil + field: attributes["level"] + - id: parse-log-level + type: severity_parser + if: attributes["log.level"] != nil + parse_from: attributes["log.level"] + - id: remove-log-level + type: remove + if: attributes["log.level"] != nil + field: attributes["log.level"] + - id: trace-router + type: router + routes: + - expr: attributes["trace_id"] != nil + output: trace-parser + - expr: attributes["traceparent"] != nil and attributes["traceparent"] matches '^[0-9a-f]{2}-(?P[0-9a-f]{32})-(?P[0-9a-f]{16})-(?P[0-9a-f]{2})$' + output: trace-parent-parser + default: noop + - id: trace-parent-parser + type: regex_parser + parse_from: attributes["traceparent"] + regex: ^[0-9a-f]{2}-(?P[0-9a-f]{32})-(?P[0-9a-f]{16})-(?P[0-9a-f]{2})$ + trace: + trace_id: + parse_from: attributes["trace_id"] + span_id: + parse_from: attributes["span_id"] + trace_flags: + parse_from: attributes["trace_flags"] + output: remove-trace-parent + - id: trace-parser + type: trace_parser + trace_id: + parse_from: attributes["trace_id"] + span_id: + parse_from: attributes["span_id"] + trace_flags: + parse_from: attributes["trace_flags"] + output: remove-trace-id + - id: remove-trace-parent + type: remove + field: attributes["traceparent"] + - id: remove-trace-id + type: remove + if: attributes["trace_id"] != nil + field: attributes["trace_id"] + - id: remove-span-id + type: remove + if: attributes["span_id"] != nil + field: attributes["span_id"] + - id: remove-trace-flags + type: remove + if: attributes["trace_flags"] != nil + field: attributes["trace_flags"] + - id: noop + type: noop +processors: + k8sattributes: + auth_type: serviceAccount + passthrough: false + extract: + metadata: + - k8s.pod.name + - k8s.node.name + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + labels: + - from: pod + key: app.kubernetes.io/name + tag_name: kyma.kubernetes_io_app_name + - from: pod + key: app + tag_name: kyma.app_name + - from: node + key: topology.kubernetes.io/region + tag_name: cloud.region + - from: node + key: topology.kubernetes.io/zone + tag_name: cloud.availability_zone + - from: node + key: node.kubernetes.io/instance-type + tag_name: host.type + - from: node + key: kubernetes.io/arch + tag_name: host.arch + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 5s + limit_percentage: 80 + spike_limit_percentage: 25 + service_enrichment: + resource_attributes: + - kyma.kubernetes_io_app_name + - kyma.app_name + transform/drop-kyma-attributes: + error_mode: ignore + log_statements: + - statements: + - delete_matching_keys(resource.attributes, "kyma.*") + transform/insert-cluster-attributes: + error_mode: ignore + log_statements: + - statements: + - set(resource.attributes["k8s.cluster.name"], "test-cluster") where resource.attributes["k8s.cluster.name"] == nil or resource.attributes["k8s.cluster.name"] == "" + - set(resource.attributes["k8s.cluster.uid"], "") where resource.attributes["k8s.cluster.uid"] == nil or resource.attributes["k8s.cluster.uid"] == "" + - set(resource.attributes["cloud.provider"], "azure") where resource.attributes["cloud.provider"] == nil or resource.attributes["cloud.provider"] == "" + transform/set-instrumentation-scope-runtime: + error_mode: ignore + log_statements: + - statements: + - set(scope.version, "main") + - set(scope.name, "io.kyma-project.telemetry/runtime") +exporters: + otlphttp/test: + endpoint: ${OTLP_ENDPOINT_TEST} + retry_on_failure: + enabled: true + initial_interval: 5s + max_interval: 30s + max_elapsed_time: 300s + auth: + authenticator: oauth2client/test diff --git a/internal/otelcollector/config/loggateway/config_builder.go b/internal/otelcollector/config/loggateway/config_builder.go index 9ccbe52fab..de03f099b7 100644 --- a/internal/otelcollector/config/loggateway/config_builder.go +++ b/internal/otelcollector/config/loggateway/config_builder.go @@ -36,6 +36,13 @@ func (b *Builder) Build(ctx context.Context, pipelines []telemetryv1alpha1.LogPi for _, pipeline := range pipelines { pipelineID := formatLogServicePipelineID(&pipeline) + + if shouldEnableOAuth2(&pipeline) { + if err := b.addOAuth2Extension(ctx, &pipeline); err != nil { + return nil, nil, err + } + } + if err := b.AddServicePipeline(ctx, &pipeline, pipelineID, b.addOTLPReceiver(), b.addMemoryLimiterProcessor(), @@ -250,6 +257,24 @@ func (b *Builder) addOTLPExporter(queueSize int) buildComponentFunc { ) } +func (b *Builder) addOAuth2Extension(ctx context.Context, pipeline *telemetryv1alpha1.LogPipeline) error { + oauth2ExtensionID := common.OAuth2ExtensionID(pipeline.Name) + + oauth2ExtensionConfig, oauth2ExtensionEnvVars, err := common.NewOAuth2ExtensionConfigBuilder( + b.Reader, + pipeline.Spec.Output.OTLP.Authentication.OAuth2, + pipeline.Name, + common.SignalTypeTrace, + ).OAuth2ExtensionConfig(ctx) + if err != nil { + return fmt.Errorf("failed to build OAuth2 extension for pipeline %s: %w", pipeline.Name, err) + } + + b.AddExtension(oauth2ExtensionID, oauth2ExtensionConfig, oauth2ExtensionEnvVars) + + return nil +} + // Helper functions func namespaceFilterProcessorConfig(namespaceSelector *telemetryv1alpha1.NamespaceSelector) *FilterProcessor { @@ -309,6 +334,10 @@ func shouldFilterByNamespace(namespaceSelector *telemetryv1alpha1.NamespaceSelec return namespaceSelector != nil && (len(namespaceSelector.Include) > 0 || len(namespaceSelector.Exclude) > 0) } +func shouldEnableOAuth2(tp *telemetryv1alpha1.LogPipeline) bool { + return tp.Spec.Output.OTLP.Authentication != nil && tp.Spec.Output.OTLP.Authentication.OAuth2 != nil +} + func formatLogServicePipelineID(lp *telemetryv1alpha1.LogPipeline) string { return fmt.Sprintf("logs/%s", lp.Name) } diff --git a/internal/otelcollector/config/loggateway/config_builder_test.go b/internal/otelcollector/config/loggateway/config_builder_test.go index 20c690bd1e..9cbc8b721d 100644 --- a/internal/otelcollector/config/loggateway/config_builder_test.go +++ b/internal/otelcollector/config/loggateway/config_builder_test.go @@ -145,6 +145,24 @@ func TestBuildConfig(t *testing.T) { }, goldenFileName: "user-defined-transform-filter.yaml", }, + { + name: "pipeline using OAuth2 authentication", + pipelines: []telemetryv1alpha1.LogPipeline{ + testutils.NewLogPipelineBuilder(). + WithName("test"). + WithApplicationInput(true). + WithOTLPOutput( + testutils.OTLPProtocol("http"), + ). + WithOAuth2( + testutils.OAuth2ClientID("client-id"), + testutils.OAuth2ClientSecret("client-secret"), + testutils.OAuth2TokenURL("https://auth.example.com/oauth2/token"), + testutils.OAuth2Scopes([]string{"logs"}), + ).Build(), + }, + goldenFileName: "oauth2-authentication.yaml", + }, } buildOptions := BuildOptions{ diff --git a/internal/otelcollector/config/loggateway/testdata/oauth2-authentication.yaml b/internal/otelcollector/config/loggateway/testdata/oauth2-authentication.yaml new file mode 100644 index 0000000000..75ea6becdd --- /dev/null +++ b/internal/otelcollector/config/loggateway/testdata/oauth2-authentication.yaml @@ -0,0 +1,139 @@ +extensions: + health_check: + endpoint: ${MY_POD_IP}:13133 + oauth2client/test: + token_url: ${OAUTH2_TOKEN_URL_TEST} + client_id: ${OAUTH2_CLIENT_ID_TEST} + client_secret: ${OAUTH2_CLIENT_SECRET_TEST} + scopes: + - logs + pprof: + endpoint: 127.0.0.1:1777 +service: + pipelines: + logs/test: + receivers: + - otlp + processors: + - memory_limiter + - transform/set-observed-time-if-zero + - k8sattributes + - istio_noise_filter + - transform/insert-cluster-attributes + - service_enrichment + - transform/drop-kyma-attributes + - istio_enrichment + - batch + exporters: + - otlphttp/test + telemetry: + metrics: + readers: + - pull: + exporter: + prometheus: + host: ${MY_POD_IP} + port: 8888 + logs: + level: info + encoding: json + extensions: + - health_check + - pprof + - oauth2client/test +receivers: + otlp: + protocols: + http: + endpoint: ${MY_POD_IP}:4318 + grpc: + endpoint: ${MY_POD_IP}:4317 +processors: + batch: + send_batch_size: 512 + timeout: 10s + send_batch_max_size: 512 + istio_enrichment: + scope_version: 1.0.0 + istio_noise_filter: {} + k8sattributes: + auth_type: serviceAccount + passthrough: false + extract: + metadata: + - k8s.pod.name + - k8s.node.name + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + labels: + - from: pod + key: app.kubernetes.io/name + tag_name: kyma.kubernetes_io_app_name + - from: pod + key: app + tag_name: kyma.app_name + - from: node + key: topology.kubernetes.io/region + tag_name: cloud.region + - from: node + key: topology.kubernetes.io/zone + tag_name: cloud.availability_zone + - from: node + key: node.kubernetes.io/instance-type + tag_name: host.type + - from: node + key: kubernetes.io/arch + tag_name: host.arch + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 1s + limit_percentage: 75 + spike_limit_percentage: 15 + service_enrichment: + resource_attributes: + - kyma.kubernetes_io_app_name + - kyma.app_name + transform/drop-kyma-attributes: + error_mode: ignore + log_statements: + - statements: + - delete_matching_keys(resource.attributes, "kyma.*") + transform/insert-cluster-attributes: + error_mode: ignore + log_statements: + - statements: + - set(resource.attributes["k8s.cluster.name"], "${KUBERNETES_SERVICE_HOST}") where resource.attributes["k8s.cluster.name"] == nil or resource.attributes["k8s.cluster.name"] == "" + - set(resource.attributes["k8s.cluster.uid"], "") where resource.attributes["k8s.cluster.uid"] == nil or resource.attributes["k8s.cluster.uid"] == "" + - set(resource.attributes["cloud.provider"], "test-cloud-provider") where resource.attributes["cloud.provider"] == nil or resource.attributes["cloud.provider"] == "" + transform/set-observed-time-if-zero: + error_mode: ignore + log_statements: + - statements: + - set(log.observed_time, Now()) + conditions: + - log.observed_time_unix_nano == 0 +exporters: + otlphttp/test: + endpoint: ${OTLP_ENDPOINT_TEST} + sending_queue: + enabled: true + queue_size: 256 + retry_on_failure: + enabled: true + initial_interval: 5s + max_interval: 30s + max_elapsed_time: 300s + auth: + authenticator: oauth2client/test diff --git a/internal/otelcollector/config/metricagent/config_builder.go b/internal/otelcollector/config/metricagent/config_builder.go index 88d5d37e23..abd7e0d173 100644 --- a/internal/otelcollector/config/metricagent/config_builder.go +++ b/internal/otelcollector/config/metricagent/config_builder.go @@ -66,11 +66,12 @@ func (b *Builder) Build(ctx context.Context, pipelines []telemetryv1alpha1.Metri b.Config = common.NewConfig() b.AddExtension(common.ComponentIDK8sLeaderElectorExtension, - common.K8sLeaderElector{ + common.K8sLeaderElectorExtension{ AuthType: "serviceAccount", LeaseName: common.K8sLeaderElectorK8sCluster, LeaseNamespace: opts.AgentNamespace, }, + nil, ) b.EnvVars = make(common.EnvVars) @@ -168,6 +169,12 @@ func (b *Builder) Build(ctx context.Context, pipelines []telemetryv1alpha1.Metri istioInputEnabled := metricpipelineutils.IsIstioInputEnabled(pipeline.Spec.Input) queueSize := common.BatchingMaxQueueSize / len(pipelines) + if shouldEnableOAuth2(&pipeline) { + if err := b.addOAuth2Extension(ctx, &pipeline); err != nil { + return nil, nil, err + } + } + if err := b.AddServicePipeline(ctx, &pipeline, outputPipelineID, // Receivers // Metrics are received from either the enrichment pipeline or directly from input pipelines, @@ -873,6 +880,26 @@ func inputRoutingConnectorConfig(outputPipelineIDs []string) common.RoutingConne } } +// Authentication extensions + +func (b *Builder) addOAuth2Extension(ctx context.Context, pipeline *telemetryv1alpha1.MetricPipeline) error { + oauth2ExtensionID := common.OAuth2ExtensionID(pipeline.Name) + + oauth2ExtensionConfig, oauth2ExtensionEnvVars, err := common.NewOAuth2ExtensionConfigBuilder( + b.Reader, + pipeline.Spec.Output.OTLP.Authentication.OAuth2, + pipeline.Name, + common.SignalTypeTrace, + ).OAuth2ExtensionConfig(ctx) + if err != nil { + return fmt.Errorf("failed to build OAuth2 extension for pipeline %s: %w", pipeline.Name, err) + } + + b.AddExtension(oauth2ExtensionID, oauth2ExtensionConfig, oauth2ExtensionEnvVars) + + return nil +} + // Helper functions for formatting IDs func formatOutputPipelineIDs(pipelines []telemetryv1alpha1.MetricPipeline) []string { @@ -1075,6 +1102,10 @@ func shouldFilterByNamespace(namespaceSelector *telemetryv1alpha1.NamespaceSelec return namespaceSelector != nil && (len(namespaceSelector.Include) > 0 || len(namespaceSelector.Exclude) > 0) } +func shouldEnableOAuth2(tp *telemetryv1alpha1.MetricPipeline) bool { + return tp.Spec.Output.OTLP.Authentication != nil && tp.Spec.Output.OTLP.Authentication.OAuth2 != nil +} + // Processor configuration functions (merged from processors.go) func dropServiceNameProcessorConfig() *common.TransformProcessor { diff --git a/internal/otelcollector/config/metricagent/config_builder_test.go b/internal/otelcollector/config/metricagent/config_builder_test.go index c43123ab90..43952c2599 100644 --- a/internal/otelcollector/config/metricagent/config_builder_test.go +++ b/internal/otelcollector/config/metricagent/config_builder_test.go @@ -389,6 +389,24 @@ func TestBuildConfig(t *testing.T) { }).Build(), }, }, + { + name: "pipeline using OAuth2 authentication", + pipelines: []telemetryv1alpha1.MetricPipeline{ + testutils.NewMetricPipelineBuilder(). + WithName("test"). + WithOTLPInput(true). + WithOTLPOutput( + testutils.OTLPProtocol("http"), + ). + WithOAuth2( + testutils.OAuth2ClientID("client-id"), + testutils.OAuth2ClientSecret("client-secret"), + testutils.OAuth2TokenURL("https://auth.example.com/oauth2/token"), + testutils.OAuth2Scopes([]string{"metrics"}), + ).Build(), + }, + goldenFileName: "oauth2-authentication.yaml", + }, } for _, tt := range tests { diff --git a/internal/otelcollector/config/metricagent/testdata/oauth2-authentication.yaml b/internal/otelcollector/config/metricagent/testdata/oauth2-authentication.yaml new file mode 100644 index 0000000000..db1f07a161 --- /dev/null +++ b/internal/otelcollector/config/metricagent/testdata/oauth2-authentication.yaml @@ -0,0 +1,141 @@ +extensions: + health_check: + endpoint: ${MY_POD_IP}:13133 + k8s_leader_elector: + auth_type: serviceAccount + lease_name: telemetry-metric-agent-k8scluster + oauth2client/test: + token_url: ${OAUTH2_TOKEN_URL_TEST} + client_id: ${OAUTH2_CLIENT_ID_TEST} + client_secret: ${OAUTH2_CLIENT_SECRET_TEST} + scopes: + - metrics + pprof: + endpoint: 127.0.0.1:1777 +service: + pipelines: + metrics/enrichment-conditional: + receivers: [] + processors: + - k8sattributes + - service_enrichment + exporters: + - routing/enrichment + metrics/output-test: + receivers: [] + processors: + - filter/drop-envoy-metrics-if-disabled + - transform/insert-cluster-attributes + - transform/drop-skip-enrichment-attribute + - transform/drop-kyma-attributes + - batch + exporters: + - otlphttp/test + telemetry: + metrics: + readers: + - pull: + exporter: + prometheus: + host: ${MY_POD_IP} + port: 8888 + logs: + level: info + encoding: json + extensions: + - health_check + - pprof + - k8s_leader_elector + - oauth2client/test +receivers: {} +processors: + batch: + send_batch_size: 1024 + timeout: 10s + send_batch_max_size: 1024 + filter/drop-envoy-metrics-if-disabled: + error_mode: ignore + metrics: + metric: + - IsMatch(name, "^envoy_.*") and resource.attributes["kyma.input.name"] == "istio" + k8sattributes: + auth_type: serviceAccount + passthrough: false + extract: + metadata: + - k8s.pod.name + - k8s.node.name + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + labels: + - from: pod + key: app.kubernetes.io/name + tag_name: kyma.kubernetes_io_app_name + - from: pod + key: app + tag_name: kyma.app_name + - from: node + key: topology.kubernetes.io/region + tag_name: cloud.region + - from: node + key: topology.kubernetes.io/zone + tag_name: cloud.availability_zone + - from: node + key: node.kubernetes.io/instance-type + tag_name: host.type + - from: node + key: kubernetes.io/arch + tag_name: host.arch + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + service_enrichment: + resource_attributes: + - kyma.kubernetes_io_app_name + - kyma.app_name + transform/drop-kyma-attributes: + error_mode: ignore + metric_statements: + - statements: + - delete_matching_keys(resource.attributes, "kyma.*") + transform/drop-skip-enrichment-attribute: + error_mode: ignore + metric_statements: + - statements: + - delete_key(resource.attributes, "io.kyma-project.telemetry.skip_enrichment") + transform/insert-cluster-attributes: + error_mode: ignore + metric_statements: + - statements: + - set(resource.attributes["k8s.cluster.name"], "") where resource.attributes["k8s.cluster.name"] == nil or resource.attributes["k8s.cluster.name"] == "" + - set(resource.attributes["k8s.cluster.uid"], "") where resource.attributes["k8s.cluster.uid"] == nil or resource.attributes["k8s.cluster.uid"] == "" +exporters: + otlphttp/test: + endpoint: ${OTLP_ENDPOINT_TEST} + tls: + insecure: true + sending_queue: + enabled: true + queue_size: 256 + retry_on_failure: + enabled: true + initial_interval: 5s + max_interval: 30s + max_elapsed_time: 300s + auth: + authenticator: oauth2client/test +connectors: + routing/enrichment: + default_pipelines: [] + error_mode: ignore + table: [] diff --git a/internal/otelcollector/config/metricgateway/config_builder.go b/internal/otelcollector/config/metricgateway/config_builder.go index 03aeeacee2..5f71745b95 100644 --- a/internal/otelcollector/config/metricgateway/config_builder.go +++ b/internal/otelcollector/config/metricgateway/config_builder.go @@ -31,11 +31,12 @@ type BuildOptions struct { func (b *Builder) Build(ctx context.Context, pipelines []telemetryv1alpha1.MetricPipeline, opts BuildOptions) (*common.Config, common.EnvVars, error) { b.Config = common.NewConfig() b.AddExtension(common.ComponentIDK8sLeaderElectorExtension, - common.K8sLeaderElector{ + common.K8sLeaderElectorExtension{ AuthType: "serviceAccount", LeaseName: common.K8sLeaderElectorKymaStats, LeaseNamespace: opts.GatewayNamespace, }, + nil, ) b.EnvVars = make(common.EnvVars) @@ -72,6 +73,13 @@ func (b *Builder) Build(ctx context.Context, pipelines []telemetryv1alpha1.Metri for _, pipeline := range pipelines { outputPipelineID := formatOutputServicePipelineID(&pipeline) + + if shouldEnableOAuth2(&pipeline) { + if err := b.addOAuth2Extension(ctx, &pipeline); err != nil { + return nil, nil, err + } + } + if err := b.AddServicePipeline(ctx, &pipeline, outputPipelineID, b.addReceiverForEnrichmentForwarder(), // Input source filters if otlp is disabled @@ -346,6 +354,26 @@ func (b *Builder) addOTLPExporter(queueSize int) buildComponentFunc { ) } +// Authentication extensions + +func (b *Builder) addOAuth2Extension(ctx context.Context, pipeline *telemetryv1alpha1.MetricPipeline) error { + oauth2ExtensionID := common.OAuth2ExtensionID(pipeline.Name) + + oauth2ExtensionConfig, oauth2ExtensionEnvVars, err := common.NewOAuth2ExtensionConfigBuilder( + b.Reader, + pipeline.Spec.Output.OTLP.Authentication.OAuth2, + pipeline.Name, + common.SignalTypeTrace, + ).OAuth2ExtensionConfig(ctx) + if err != nil { + return fmt.Errorf("failed to build OAuth2 extension for pipeline %s: %w", pipeline.Name, err) + } + + b.AddExtension(oauth2ExtensionID, oauth2ExtensionConfig, oauth2ExtensionEnvVars) + + return nil +} + // Helper functions func shouldFilterByNamespace(namespaceSelector *telemetryv1alpha1.NamespaceSelector) bool { @@ -402,6 +430,11 @@ func formatUserDefinedTransformProcessorID(mp *telemetryv1alpha1.MetricPipeline) func formatUserDefinedFilterProcessorID(mp *telemetryv1alpha1.MetricPipeline) string { return fmt.Sprintf(common.ComponentIDUserDefinedFilterProcessor, mp.Name) } + func formatOutputServicePipelineID(mp *telemetryv1alpha1.MetricPipeline) string { return fmt.Sprintf("metrics/%s-output", mp.Name) } + +func shouldEnableOAuth2(tp *telemetryv1alpha1.MetricPipeline) bool { + return tp.Spec.Output.OTLP.Authentication != nil && tp.Spec.Output.OTLP.Authentication.OAuth2 != nil +} diff --git a/internal/otelcollector/config/metricgateway/config_builder_test.go b/internal/otelcollector/config/metricgateway/config_builder_test.go index 00d9309b5e..866c8ad371 100644 --- a/internal/otelcollector/config/metricgateway/config_builder_test.go +++ b/internal/otelcollector/config/metricgateway/config_builder_test.go @@ -187,6 +187,24 @@ func TestBuildConfig(t *testing.T) { }).Build(), }, }, + { + name: "pipeline using OAuth2 authentication", + pipelines: []telemetryv1alpha1.MetricPipeline{ + testutils.NewMetricPipelineBuilder(). + WithName("test"). + WithOTLPInput(true). + WithOTLPOutput( + testutils.OTLPProtocol("http"), + ). + WithOAuth2( + testutils.OAuth2ClientID("client-id"), + testutils.OAuth2ClientSecret("client-secret"), + testutils.OAuth2TokenURL("https://auth.example.com/oauth2/token"), + testutils.OAuth2Scopes([]string{"metrics"}), + ).Build(), + }, + goldenFileName: "oauth2-authentication.yaml", + }, } buildOptions := BuildOptions{ diff --git a/internal/otelcollector/config/metricgateway/testdata/oauth2-authentication.yaml b/internal/otelcollector/config/metricgateway/testdata/oauth2-authentication.yaml new file mode 100644 index 0000000000..8287f4d6fd --- /dev/null +++ b/internal/otelcollector/config/metricgateway/testdata/oauth2-authentication.yaml @@ -0,0 +1,189 @@ +extensions: + health_check: + endpoint: ${MY_POD_IP}:13133 + k8s_leader_elector: + auth_type: serviceAccount + lease_name: telemetry-metric-gateway-kymastats + oauth2client/test: + token_url: ${OAUTH2_TOKEN_URL_TEST} + client_id: ${OAUTH2_CLIENT_ID_TEST} + client_secret: ${OAUTH2_CLIENT_SECRET_TEST} + scopes: + - metrics + pprof: + endpoint: 127.0.0.1:1777 +service: + pipelines: + metrics/enrichment: + receivers: + - forward/input + processors: + - memory_limiter + - transform/set-instrumentation-scope-kyma + - k8sattributes + - service_enrichment + - transform/insert-cluster-attributes + exporters: + - forward/enrichment + metrics/input-kyma-stats: + receivers: + - kymastats + processors: + - transform/set-kyma-input-name-kyma + exporters: + - forward/input + metrics/input-otlp: + receivers: + - otlp + processors: + - transform/set-kyma-input-name-otlp + exporters: + - forward/input + metrics/test-output: + receivers: + - forward/enrichment + processors: + - transform/drop-kyma-attributes + - batch + exporters: + - otlphttp/test + telemetry: + metrics: + readers: + - pull: + exporter: + prometheus: + host: ${MY_POD_IP} + port: 8888 + logs: + level: info + encoding: json + extensions: + - health_check + - pprof + - k8s_leader_elector + - oauth2client/test +receivers: + kymastats: + auth_type: serviceAccount + collection_interval: 30s + resources: + - group: operator.kyma-project.io + version: v1alpha1 + resource: telemetries + - group: telemetry.kyma-project.io + version: v1alpha1 + resource: logpipelines + - group: telemetry.kyma-project.io + version: v1alpha1 + resource: tracepipelines + - group: telemetry.kyma-project.io + version: v1alpha1 + resource: metricpipelines + k8s_leader_elector: k8s_leader_elector + otlp: + protocols: + http: + endpoint: ${MY_POD_IP}:4318 + grpc: + endpoint: ${MY_POD_IP}:4317 +processors: + batch: + send_batch_size: 1024 + timeout: 10s + send_batch_max_size: 1024 + k8sattributes: + auth_type: serviceAccount + passthrough: false + extract: + metadata: + - k8s.pod.name + - k8s.node.name + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + labels: + - from: pod + key: app.kubernetes.io/name + tag_name: kyma.kubernetes_io_app_name + - from: pod + key: app + tag_name: kyma.app_name + - from: node + key: topology.kubernetes.io/region + tag_name: cloud.region + - from: node + key: topology.kubernetes.io/zone + tag_name: cloud.availability_zone + - from: node + key: node.kubernetes.io/instance-type + tag_name: host.type + - from: node + key: kubernetes.io/arch + tag_name: host.arch + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 1s + limit_percentage: 75 + spike_limit_percentage: 15 + service_enrichment: + resource_attributes: + - kyma.kubernetes_io_app_name + - kyma.app_name + transform/drop-kyma-attributes: + error_mode: ignore + metric_statements: + - statements: + - delete_matching_keys(resource.attributes, "kyma.*") + transform/insert-cluster-attributes: + error_mode: ignore + metric_statements: + - statements: + - set(resource.attributes["k8s.cluster.name"], "${KUBERNETES_SERVICE_HOST}") where resource.attributes["k8s.cluster.name"] == nil or resource.attributes["k8s.cluster.name"] == "" + - set(resource.attributes["k8s.cluster.uid"], "") where resource.attributes["k8s.cluster.uid"] == nil or resource.attributes["k8s.cluster.uid"] == "" + - set(resource.attributes["cloud.provider"], "test-cloud-provider") where resource.attributes["cloud.provider"] == nil or resource.attributes["cloud.provider"] == "" + transform/set-instrumentation-scope-kyma: + error_mode: ignore + metric_statements: + - statements: + - set(scope.version, "") where scope.name == "github.com/kyma-project/opentelemetry-collector-components/receiver/kymastatsreceiver" + - set(scope.name, "io.kyma-project.telemetry/kyma") where scope.name == "github.com/kyma-project/opentelemetry-collector-components/receiver/kymastatsreceiver" + transform/set-kyma-input-name-kyma: + error_mode: ignore + metric_statements: + - statements: + - set(resource.attributes["kyma.input.name"], "kyma") + transform/set-kyma-input-name-otlp: + error_mode: ignore + metric_statements: + - statements: + - set(resource.attributes["kyma.input.name"], "otlp") +exporters: + otlphttp/test: + endpoint: ${OTLP_ENDPOINT_TEST} + tls: + insecure: true + sending_queue: + enabled: true + queue_size: 256 + retry_on_failure: + enabled: true + initial_interval: 5s + max_interval: 30s + max_elapsed_time: 300s + auth: + authenticator: oauth2client/test +connectors: + forward/enrichment: {} + forward/input: {} diff --git a/internal/otelcollector/config/tracegateway/config_builder.go b/internal/otelcollector/config/tracegateway/config_builder.go index 90d9ea93a4..30e4f8edc8 100644 --- a/internal/otelcollector/config/tracegateway/config_builder.go +++ b/internal/otelcollector/config/tracegateway/config_builder.go @@ -34,6 +34,13 @@ func (b *Builder) Build(ctx context.Context, pipelines []telemetryv1alpha1.Trace for _, pipeline := range pipelines { pipelineID := formatTraceServicePipelineID(&pipeline) + + if shouldEnableOAuth2(&pipeline) { + if err := b.addOAuth2Extension(ctx, &pipeline); err != nil { + return nil, nil, err + } + } + if err := b.AddServicePipeline(ctx, &pipeline, pipelineID, b.addOTLPReceiver(), b.addMemoryLimiterProcessor(), @@ -194,6 +201,28 @@ func (b *Builder) addOTLPExporter(queueSize int) buildComponentFunc { ) } +func (b *Builder) addOAuth2Extension(ctx context.Context, pipeline *telemetryv1alpha1.TracePipeline) error { + oauth2ExtensionID := common.OAuth2ExtensionID(pipeline.Name) + + oauth2ExtensionConfig, oauth2ExtensionEnvVars, err := common.NewOAuth2ExtensionConfigBuilder( + b.Reader, + pipeline.Spec.Output.OTLP.Authentication.OAuth2, + pipeline.Name, + common.SignalTypeTrace, + ).OAuth2ExtensionConfig(ctx) + if err != nil { + return fmt.Errorf("failed to build OAuth2 extension for pipeline %s: %w", pipeline.Name, err) + } + + b.AddExtension(oauth2ExtensionID, oauth2ExtensionConfig, oauth2ExtensionEnvVars) + + return nil +} + +func shouldEnableOAuth2(tp *telemetryv1alpha1.TracePipeline) bool { + return tp.Spec.Output.OTLP.Authentication != nil && tp.Spec.Output.OTLP.Authentication.OAuth2 != nil +} + func formatTraceServicePipelineID(tp *telemetryv1alpha1.TracePipeline) string { return fmt.Sprintf("traces/%s", tp.Name) } diff --git a/internal/otelcollector/config/tracegateway/config_builder_test.go b/internal/otelcollector/config/tracegateway/config_builder_test.go index 34a1090db9..ac9bbbaefe 100644 --- a/internal/otelcollector/config/tracegateway/config_builder_test.go +++ b/internal/otelcollector/config/tracegateway/config_builder_test.go @@ -111,6 +111,23 @@ func TestBuildConfig(t *testing.T) { }, goldenFileName: "user-defined-transform-filter.yaml", }, + { + name: "pipeline using OAuth2 authentication", + pipelines: []telemetryv1alpha1.TracePipeline{ + testutils.NewTracePipelineBuilder(). + WithName("test"). + WithOTLPOutput( + testutils.OTLPProtocol("http"), + ). + WithOAuth2( + testutils.OAuth2ClientID("client-id"), + testutils.OAuth2ClientSecret("client-secret"), + testutils.OAuth2TokenURL("https://auth.example.com/oauth2/token"), + testutils.OAuth2Scopes([]string{"traces"}), + ).Build(), + }, + goldenFileName: "oauth2-authentication.yaml", + }, } buildOptions := BuildOptions{ diff --git a/internal/otelcollector/config/tracegateway/testdata/oauth2-authentication.yaml b/internal/otelcollector/config/tracegateway/testdata/oauth2-authentication.yaml new file mode 100644 index 0000000000..e5f7950cfc --- /dev/null +++ b/internal/otelcollector/config/tracegateway/testdata/oauth2-authentication.yaml @@ -0,0 +1,128 @@ +extensions: + health_check: + endpoint: ${MY_POD_IP}:13133 + oauth2client/test: + token_url: ${OAUTH2_TOKEN_URL_TEST} + client_id: ${OAUTH2_CLIENT_ID_TEST} + client_secret: ${OAUTH2_CLIENT_SECRET_TEST} + scopes: + - traces + pprof: + endpoint: 127.0.0.1:1777 +service: + pipelines: + traces/test: + receivers: + - otlp + processors: + - memory_limiter + - k8sattributes + - istio_noise_filter + - transform/insert-cluster-attributes + - service_enrichment + - transform/drop-kyma-attributes + - batch + exporters: + - otlphttp/test + telemetry: + metrics: + readers: + - pull: + exporter: + prometheus: + host: ${MY_POD_IP} + port: 8888 + logs: + level: info + encoding: json + extensions: + - health_check + - pprof + - oauth2client/test +receivers: + otlp: + protocols: + http: + endpoint: ${MY_POD_IP}:4318 + grpc: + endpoint: ${MY_POD_IP}:4317 +processors: + batch: + send_batch_size: 512 + timeout: 10s + send_batch_max_size: 512 + istio_noise_filter: {} + k8sattributes: + auth_type: serviceAccount + passthrough: false + extract: + metadata: + - k8s.pod.name + - k8s.node.name + - k8s.namespace.name + - k8s.deployment.name + - k8s.statefulset.name + - k8s.daemonset.name + - k8s.cronjob.name + - k8s.job.name + labels: + - from: pod + key: app.kubernetes.io/name + tag_name: kyma.kubernetes_io_app_name + - from: pod + key: app + tag_name: kyma.app_name + - from: node + key: topology.kubernetes.io/region + tag_name: cloud.region + - from: node + key: topology.kubernetes.io/zone + tag_name: cloud.availability_zone + - from: node + key: node.kubernetes.io/instance-type + tag_name: host.type + - from: node + key: kubernetes.io/arch + tag_name: host.arch + pod_association: + - sources: + - from: resource_attribute + name: k8s.pod.ip + - sources: + - from: resource_attribute + name: k8s.pod.uid + - sources: + - from: connection + memory_limiter: + check_interval: 1s + limit_percentage: 75 + spike_limit_percentage: 15 + service_enrichment: + resource_attributes: + - kyma.kubernetes_io_app_name + - kyma.app_name + transform/drop-kyma-attributes: + error_mode: ignore + trace_statements: + - statements: + - delete_matching_keys(resource.attributes, "kyma.*") + transform/insert-cluster-attributes: + error_mode: ignore + trace_statements: + - statements: + - set(resource.attributes["k8s.cluster.name"], "${KUBERNETES_SERVICE_HOST}") where resource.attributes["k8s.cluster.name"] == nil or resource.attributes["k8s.cluster.name"] == "" + - set(resource.attributes["k8s.cluster.uid"], "") where resource.attributes["k8s.cluster.uid"] == nil or resource.attributes["k8s.cluster.uid"] == "" + - set(resource.attributes["cloud.provider"], "test-cloud-provider") where resource.attributes["cloud.provider"] == nil or resource.attributes["cloud.provider"] == "" +exporters: + otlphttp/test: + endpoint: ${OTLP_ENDPOINT_TEST} + sending_queue: + enabled: true + queue_size: 256 + retry_on_failure: + enabled: true + initial_interval: 5s + max_interval: 30s + max_elapsed_time: 300s + auth: + authenticator: oauth2client/test diff --git a/internal/reconciler/logpipeline/fluentbit/interfaces.go b/internal/reconciler/logpipeline/fluentbit/interfaces.go index 26688f276d..e1de1719ca 100644 --- a/internal/reconciler/logpipeline/fluentbit/interfaces.go +++ b/internal/reconciler/logpipeline/fluentbit/interfaces.go @@ -11,6 +11,7 @@ import ( "github.com/kyma-project/telemetry-manager/internal/fluentbit/config/builder" "github.com/kyma-project/telemetry-manager/internal/resources/fluentbit" "github.com/kyma-project/telemetry-manager/internal/selfmonitor/prober" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" "github.com/kyma-project/telemetry-manager/internal/validators/tlscert" ) @@ -81,7 +82,7 @@ type EndpointValidator interface { // Validate checks if the endpoint configuration is valid for the specified protocol. // It verifies the endpoint format, DNS resolution, and protocol compatibility. // Returns an error if the endpoint is invalid, unreachable, or incompatible with the protocol. - Validate(ctx context.Context, endpoint *telemetryv1alpha1.ValueType, protocol string) error + Validate(ctx context.Context, params endpoint.EndpointValidationParams) error } // TLSCertValidator validates TLS certificate configurations for secure connections. @@ -90,7 +91,7 @@ type TLSCertValidator interface { // Validate checks if the TLS certificate bundle is valid and not expired. // It verifies the certificate chain, expiration dates, and proper encoding. // Returns an error if the certificate is invalid, expired, or about to expire. - Validate(ctx context.Context, config tlscert.TLSBundle) error + Validate(ctx context.Context, config tlscert.TLSValidationParams) error } // SecretRefValidator validates secret references in LogPipeline resources. diff --git a/internal/reconciler/logpipeline/fluentbit/validator.go b/internal/reconciler/logpipeline/fluentbit/validator.go index fc808f01f0..3664ff5b4c 100644 --- a/internal/reconciler/logpipeline/fluentbit/validator.go +++ b/internal/reconciler/logpipeline/fluentbit/validator.go @@ -74,13 +74,16 @@ func (v *Validator) Validate(ctx context.Context, pipeline *telemetryv1alpha1.Lo } if pipeline.Spec.Output.FluentBitHTTP != nil { - if err := v.EndpointValidator.Validate(ctx, &pipeline.Spec.Output.FluentBitHTTP.Host, endpoint.FluentdProtocolHTTP); err != nil { + if err := v.EndpointValidator.Validate(ctx, endpoint.EndpointValidationParams{ + Endpoint: &pipeline.Spec.Output.FluentBitHTTP.Host, + Protocol: endpoint.FluentdProtocolHTTP, + }); err != nil { return err } } if tlsValidationRequired(pipeline) { - tlsConfig := tlscert.TLSBundle{ + tlsConfig := tlscert.TLSValidationParams{ Cert: pipeline.Spec.Output.FluentBitHTTP.TLS.Cert, Key: pipeline.Spec.Output.FluentBitHTTP.TLS.Key, CA: pipeline.Spec.Output.FluentBitHTTP.TLS.CA, diff --git a/internal/reconciler/logpipeline/otel/interfaces.go b/internal/reconciler/logpipeline/otel/interfaces.go index 4eea588574..9c044e2334 100644 --- a/internal/reconciler/logpipeline/otel/interfaces.go +++ b/internal/reconciler/logpipeline/otel/interfaces.go @@ -13,6 +13,7 @@ import ( "github.com/kyma-project/telemetry-manager/internal/otelcollector/config/loggateway" "github.com/kyma-project/telemetry-manager/internal/resources/otelcollector" "github.com/kyma-project/telemetry-manager/internal/selfmonitor/prober" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" "github.com/kyma-project/telemetry-manager/internal/validators/tlscert" ) @@ -111,7 +112,7 @@ type EndpointValidator interface { // Validate checks if the endpoint configuration is valid for the specified protocol. // It verifies the endpoint format, DNS resolution, and protocol compatibility. // Returns an error if the endpoint is invalid, unreachable, or incompatible with the protocol. - Validate(ctx context.Context, endpoint *telemetryv1alpha1.ValueType, protocol string) error + Validate(ctx context.Context, params endpoint.EndpointValidationParams) error } // TLSCertValidator validates TLS certificate configurations for secure connections. @@ -120,7 +121,7 @@ type TLSCertValidator interface { // Validate checks if the TLS certificate bundle is valid and not expired. // It verifies the certificate chain, expiration dates, and proper encoding. // Returns an error if the certificate is invalid, expired, or about to expire. - Validate(ctx context.Context, config tlscert.TLSBundle) error + Validate(ctx context.Context, config tlscert.TLSValidationParams) error } // SecretRefValidator validates secret references in LogPipeline resources. diff --git a/internal/reconciler/logpipeline/otel/validator.go b/internal/reconciler/logpipeline/otel/validator.go index c335077fce..b6a6be71b3 100644 --- a/internal/reconciler/logpipeline/otel/validator.go +++ b/internal/reconciler/logpipeline/otel/validator.go @@ -4,6 +4,7 @@ import ( "context" telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" "github.com/kyma-project/telemetry-manager/internal/validators/tlscert" ) @@ -80,13 +81,23 @@ func (v *Validator) Validate(ctx context.Context, pipeline *telemetryv1alpha1.Lo } if pipeline.Spec.Output.OTLP != nil { - if err := v.EndpointValidator.Validate(ctx, &pipeline.Spec.Output.OTLP.Endpoint, pipeline.Spec.Output.OTLP.Protocol); err != nil { + var oauth2 *telemetryv1alpha1.OAuth2Options = nil + if pipeline.Spec.Output.OTLP.Authentication != nil { + oauth2 = pipeline.Spec.Output.OTLP.Authentication.OAuth2 + } + + if err := v.EndpointValidator.Validate(ctx, endpoint.EndpointValidationParams{ + Endpoint: &pipeline.Spec.Output.OTLP.Endpoint, + Protocol: pipeline.Spec.Output.OTLP.Protocol, + OTLPTLS: pipeline.Spec.Output.OTLP.TLS, + OTLPOAuth2: oauth2, + }); err != nil { return err } } if tlsValidationRequired(pipeline) { - tlsConfig := tlscert.TLSBundle{ + tlsConfig := tlscert.TLSValidationParams{ Cert: pipeline.Spec.Output.OTLP.TLS.Cert, Key: pipeline.Spec.Output.OTLP.TLS.Key, CA: pipeline.Spec.Output.OTLP.TLS.CA, diff --git a/internal/reconciler/logpipeline/stubs/endpoint_validator.go b/internal/reconciler/logpipeline/stubs/endpoint_validator.go index 91afd097a9..0a13b8369e 100644 --- a/internal/reconciler/logpipeline/stubs/endpoint_validator.go +++ b/internal/reconciler/logpipeline/stubs/endpoint_validator.go @@ -3,7 +3,7 @@ package stubs import ( "context" - telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" ) type EndpointValidator struct { @@ -16,6 +16,6 @@ func NewEndpointValidator(err error) *EndpointValidator { } } -func (e *EndpointValidator) Validate(ctx context.Context, endpoint *telemetryv1alpha1.ValueType, protocol string) error { +func (e *EndpointValidator) Validate(ctx context.Context, params endpoint.EndpointValidationParams) error { return e.err } diff --git a/internal/reconciler/logpipeline/stubs/tls_cert_validator.go b/internal/reconciler/logpipeline/stubs/tls_cert_validator.go index 0e064e6663..31212a5197 100644 --- a/internal/reconciler/logpipeline/stubs/tls_cert_validator.go +++ b/internal/reconciler/logpipeline/stubs/tls_cert_validator.go @@ -16,6 +16,6 @@ func NewTLSCertValidator(err error) *TLSCertValidator { } } -func (t *TLSCertValidator) Validate(ctx context.Context, config tlscert.TLSBundle) error { +func (t *TLSCertValidator) Validate(ctx context.Context, config tlscert.TLSValidationParams) error { return t.err } diff --git a/internal/reconciler/metricpipeline/interfaces.go b/internal/reconciler/metricpipeline/interfaces.go index 41c4eb86cd..b79fc65149 100644 --- a/internal/reconciler/metricpipeline/interfaces.go +++ b/internal/reconciler/metricpipeline/interfaces.go @@ -13,6 +13,7 @@ import ( "github.com/kyma-project/telemetry-manager/internal/overrides" "github.com/kyma-project/telemetry-manager/internal/resources/otelcollector" "github.com/kyma-project/telemetry-manager/internal/selfmonitor/prober" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" "github.com/kyma-project/telemetry-manager/internal/validators/tlscert" ) @@ -113,7 +114,7 @@ type EndpointValidator interface { // Validate checks if the endpoint configuration is valid for the specified protocol. // It verifies the endpoint format, DNS resolution, and protocol compatibility. // Returns an error if the endpoint is invalid, unreachable, or incompatible with the protocol. - Validate(ctx context.Context, endpoint *telemetryv1alpha1.ValueType, protocol string) error + Validate(ctx context.Context, params endpoint.EndpointValidationParams) error } // TLSCertValidator validates TLS certificate configurations for secure connections. @@ -122,7 +123,7 @@ type TLSCertValidator interface { // Validate checks if the TLS certificate bundle is valid and not expired. // It verifies the certificate chain, expiration dates, and proper encoding. // Returns an error if the certificate is invalid, expired, or about to expire. - Validate(ctx context.Context, config tlscert.TLSBundle) error + Validate(ctx context.Context, config tlscert.TLSValidationParams) error } // SecretRefValidator validates secret references in MetricPipeline resources. diff --git a/internal/reconciler/metricpipeline/reconciler_test.go b/internal/reconciler/metricpipeline/reconciler_test.go index b44fe0488e..5c4ffbb203 100644 --- a/internal/reconciler/metricpipeline/reconciler_test.go +++ b/internal/reconciler/metricpipeline/reconciler_test.go @@ -539,7 +539,7 @@ func TestTLSCertificateValidation(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - pipeline := testutils.NewMetricPipelineBuilder().WithOTLPOutput(testutils.OTLPClientTLSFromString("ca", "fooCert", "fooKey")).Build() + pipeline := testutils.NewMetricPipelineBuilder().WithOTLPOutput(testutils.OTLPClientMTLSFromString("ca", "fooCert", "fooKey")).Build() fakeClient := newTestClient(t, &pipeline) gatewayConfigBuilderMock := &mocks.GatewayConfigBuilder{} diff --git a/internal/reconciler/metricpipeline/stubs/endpoint_validator.go b/internal/reconciler/metricpipeline/stubs/endpoint_validator.go index 91afd097a9..0a13b8369e 100644 --- a/internal/reconciler/metricpipeline/stubs/endpoint_validator.go +++ b/internal/reconciler/metricpipeline/stubs/endpoint_validator.go @@ -3,7 +3,7 @@ package stubs import ( "context" - telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" ) type EndpointValidator struct { @@ -16,6 +16,6 @@ func NewEndpointValidator(err error) *EndpointValidator { } } -func (e *EndpointValidator) Validate(ctx context.Context, endpoint *telemetryv1alpha1.ValueType, protocol string) error { +func (e *EndpointValidator) Validate(ctx context.Context, params endpoint.EndpointValidationParams) error { return e.err } diff --git a/internal/reconciler/metricpipeline/stubs/tls_cert_validator.go b/internal/reconciler/metricpipeline/stubs/tls_cert_validator.go index 0e064e6663..31212a5197 100644 --- a/internal/reconciler/metricpipeline/stubs/tls_cert_validator.go +++ b/internal/reconciler/metricpipeline/stubs/tls_cert_validator.go @@ -16,6 +16,6 @@ func NewTLSCertValidator(err error) *TLSCertValidator { } } -func (t *TLSCertValidator) Validate(ctx context.Context, config tlscert.TLSBundle) error { +func (t *TLSCertValidator) Validate(ctx context.Context, config tlscert.TLSValidationParams) error { return t.err } diff --git a/internal/reconciler/metricpipeline/validator.go b/internal/reconciler/metricpipeline/validator.go index d84df223f4..5f9992e465 100644 --- a/internal/reconciler/metricpipeline/validator.go +++ b/internal/reconciler/metricpipeline/validator.go @@ -4,6 +4,7 @@ import ( "context" telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" "github.com/kyma-project/telemetry-manager/internal/validators/tlscert" ) @@ -79,13 +80,23 @@ func (v *Validator) validate(ctx context.Context, pipeline *telemetryv1alpha1.Me } if pipeline.Spec.Output.OTLP != nil { - if err := v.EndpointValidator.Validate(ctx, &pipeline.Spec.Output.OTLP.Endpoint, pipeline.Spec.Output.OTLP.Protocol); err != nil { + var oauth2 *telemetryv1alpha1.OAuth2Options = nil + if pipeline.Spec.Output.OTLP.Authentication != nil { + oauth2 = pipeline.Spec.Output.OTLP.Authentication.OAuth2 + } + + if err := v.EndpointValidator.Validate(ctx, endpoint.EndpointValidationParams{ + Endpoint: &pipeline.Spec.Output.OTLP.Endpoint, + Protocol: pipeline.Spec.Output.OTLP.Protocol, + OTLPOAuth2: oauth2, + OTLPTLS: pipeline.Spec.Output.OTLP.TLS, + }); err != nil { return err } } if tlsValidationRequired(pipeline) { - tlsConfig := tlscert.TLSBundle{ + tlsConfig := tlscert.TLSValidationParams{ Cert: pipeline.Spec.Output.OTLP.TLS.Cert, Key: pipeline.Spec.Output.OTLP.TLS.Key, CA: pipeline.Spec.Output.OTLP.TLS.CA, diff --git a/internal/reconciler/tracepipeline/interfaces.go b/internal/reconciler/tracepipeline/interfaces.go index 6c7c05bc47..050f797021 100644 --- a/internal/reconciler/tracepipeline/interfaces.go +++ b/internal/reconciler/tracepipeline/interfaces.go @@ -12,6 +12,7 @@ import ( "github.com/kyma-project/telemetry-manager/internal/overrides" "github.com/kyma-project/telemetry-manager/internal/resources/otelcollector" "github.com/kyma-project/telemetry-manager/internal/selfmonitor/prober" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" "github.com/kyma-project/telemetry-manager/internal/validators/tlscert" ) @@ -65,7 +66,7 @@ type IstioStatusChecker interface { // EndpointValidator validates trace pipeline endpoint configurations. type EndpointValidator interface { // Validate checks if the endpoint configuration is valid for the specified protocol. - Validate(ctx context.Context, endpoint *telemetryv1alpha1.ValueType, protocol string) error + Validate(ctx context.Context, params endpoint.EndpointValidationParams) error } // SecretRefValidator validates secret references in TracePipeline resources. @@ -77,7 +78,7 @@ type SecretRefValidator interface { // TLSCertValidator validates TLS certificate configurations. type TLSCertValidator interface { // Validate checks if the TLS certificate bundle is valid and not expired. - Validate(ctx context.Context, config tlscert.TLSBundle) error + Validate(ctx context.Context, config tlscert.TLSValidationParams) error } // TransformSpecValidator validates transform specifications in pipeline configurations. diff --git a/internal/reconciler/tracepipeline/reconciler_test.go b/internal/reconciler/tracepipeline/reconciler_test.go index 597d81c1e7..dcf5a71dfe 100644 --- a/internal/reconciler/tracepipeline/reconciler_test.go +++ b/internal/reconciler/tracepipeline/reconciler_test.go @@ -414,7 +414,7 @@ func TestTLSCertificateValidation(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - pipeline := testutils.NewTracePipelineBuilder().WithOTLPOutput(testutils.OTLPClientTLSFromString("ca", "fooCert", "fooKey")).Build() + pipeline := testutils.NewTracePipelineBuilder().WithOTLPOutput(testutils.OTLPClientMTLSFromString("ca", "fooCert", "fooKey")).Build() fakeClient := newTestClient(t, &pipeline) gatewayConfigBuilderMock := &mocks.GatewayConfigBuilder{} diff --git a/internal/reconciler/tracepipeline/stubs/endpoint_validator.go b/internal/reconciler/tracepipeline/stubs/endpoint_validator.go index 91afd097a9..0a13b8369e 100644 --- a/internal/reconciler/tracepipeline/stubs/endpoint_validator.go +++ b/internal/reconciler/tracepipeline/stubs/endpoint_validator.go @@ -3,7 +3,7 @@ package stubs import ( "context" - telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" ) type EndpointValidator struct { @@ -16,6 +16,6 @@ func NewEndpointValidator(err error) *EndpointValidator { } } -func (e *EndpointValidator) Validate(ctx context.Context, endpoint *telemetryv1alpha1.ValueType, protocol string) error { +func (e *EndpointValidator) Validate(ctx context.Context, params endpoint.EndpointValidationParams) error { return e.err } diff --git a/internal/reconciler/tracepipeline/stubs/tls_cert_validator.go b/internal/reconciler/tracepipeline/stubs/tls_cert_validator.go index 0e064e6663..31212a5197 100644 --- a/internal/reconciler/tracepipeline/stubs/tls_cert_validator.go +++ b/internal/reconciler/tracepipeline/stubs/tls_cert_validator.go @@ -16,6 +16,6 @@ func NewTLSCertValidator(err error) *TLSCertValidator { } } -func (t *TLSCertValidator) Validate(ctx context.Context, config tlscert.TLSBundle) error { +func (t *TLSCertValidator) Validate(ctx context.Context, config tlscert.TLSValidationParams) error { return t.err } diff --git a/internal/reconciler/tracepipeline/validator.go b/internal/reconciler/tracepipeline/validator.go index d9ffb94fe9..57a062cc1e 100644 --- a/internal/reconciler/tracepipeline/validator.go +++ b/internal/reconciler/tracepipeline/validator.go @@ -4,6 +4,7 @@ import ( "context" telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + "github.com/kyma-project/telemetry-manager/internal/validators/endpoint" "github.com/kyma-project/telemetry-manager/internal/validators/tlscert" ) @@ -79,13 +80,23 @@ func (v *Validator) validate(ctx context.Context, pipeline *telemetryv1alpha1.Tr } if pipeline.Spec.Output.OTLP != nil { - if err := v.EndpointValidator.Validate(ctx, &pipeline.Spec.Output.OTLP.Endpoint, pipeline.Spec.Output.OTLP.Protocol); err != nil { + var oauth2 *telemetryv1alpha1.OAuth2Options = nil + if pipeline.Spec.Output.OTLP.Authentication != nil { + oauth2 = pipeline.Spec.Output.OTLP.Authentication.OAuth2 + } + + if err := v.EndpointValidator.Validate(ctx, endpoint.EndpointValidationParams{ + Endpoint: &pipeline.Spec.Output.OTLP.Endpoint, + Protocol: pipeline.Spec.Output.OTLP.Protocol, + OTLPTLS: pipeline.Spec.Output.OTLP.TLS, + OTLPOAuth2: oauth2, + }); err != nil { return err } } if tlsValidationRequired(pipeline) { - tlsConfig := tlscert.TLSBundle{ + tlsConfig := tlscert.TLSValidationParams{ Cert: pipeline.Spec.Output.OTLP.TLS.Cert, Key: pipeline.Spec.Output.OTLP.TLS.Key, CA: pipeline.Spec.Output.OTLP.TLS.CA, diff --git a/internal/utils/metricpipeline/metricpipeline.go b/internal/utils/metricpipeline/metricpipeline.go index 7656f1cc6c..3855d09b1f 100644 --- a/internal/utils/metricpipeline/metricpipeline.go +++ b/internal/utils/metricpipeline/metricpipeline.go @@ -11,8 +11,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" - "github.com/kyma-project/telemetry-manager/internal/otelcollector/config/common" "github.com/kyma-project/telemetry-manager/internal/otelcollector/ports" + sharedtypesutils "github.com/kyma-project/telemetry-manager/internal/utils/sharedtypes" ) func IsIstioInputEnabled(input telemetryv1alpha1.MetricPipelineInput) bool { @@ -116,7 +116,7 @@ func OTLPOutputPorts(ctx context.Context, c client.Reader, allPipelines []teleme backendPorts := []string{} for _, pipeline := range allPipelines { - endpoint, err := common.ResolveValue(ctx, c, pipeline.Spec.Output.OTLP.Endpoint) + endpoint, err := sharedtypesutils.ResolveValue(ctx, c, pipeline.Spec.Output.OTLP.Endpoint) if err != nil { return nil, fmt.Errorf("failed to resolve the value of the OTLP output endpoint: %w", err) } diff --git a/internal/utils/sharedtypes/sharedtypes.go b/internal/utils/sharedtypes/sharedtypes.go index 65800f5f65..215d05b599 100644 --- a/internal/utils/sharedtypes/sharedtypes.go +++ b/internal/utils/sharedtypes/sharedtypes.go @@ -1,8 +1,18 @@ package sharedtypes import ( + "context" + "errors" + + "sigs.k8s.io/controller-runtime/pkg/client" + telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" telemetryv1beta1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1beta1" + "github.com/kyma-project/telemetry-manager/internal/validators/secretref" +) + +var ( + ErrValueOrSecretRefUndefined = errors.New("either value or secret key reference must be defined") ) func IsValid(v *telemetryv1alpha1.ValueType) bool { @@ -37,6 +47,18 @@ func IsValidBeta(v *telemetryv1beta1.ValueType) bool { v.ValueFrom.SecretKeyRef.Namespace != "" } +func ResolveValue(ctx context.Context, c client.Reader, value telemetryv1alpha1.ValueType) ([]byte, error) { + if value.Value != "" { + return []byte(value.Value), nil + } + + if value.ValueFrom.SecretKeyRef != nil { + return secretref.GetValue(ctx, c, *value.ValueFrom.SecretKeyRef) + } + + return nil, ErrValueOrSecretRefUndefined +} + func IsFilterDefined(filters []telemetryv1alpha1.FilterSpec) bool { return len(filters) > 0 } diff --git a/internal/utils/sharedtypes/sharedtypes_test.go b/internal/utils/sharedtypes/sharedtypes_test.go index 5c8dace60f..c1353a4aa5 100644 --- a/internal/utils/sharedtypes/sharedtypes_test.go +++ b/internal/utils/sharedtypes/sharedtypes_test.go @@ -1,9 +1,15 @@ package sharedtypes import ( + "context" + "errors" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client/fake" telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" telemetryv1beta1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1beta1" @@ -225,6 +231,92 @@ func TestIsValidBeta(t *testing.T) { } } +func TestResolveValue(t *testing.T) { + ctx := context.Background() + + testSecret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "test-key": []byte("secret-value"), + }, + } + + client := fake.NewClientBuilder().WithObjects(&testSecret).Build() + + tests := []struct { + name string + value telemetryv1alpha1.ValueType + expected []byte + expectedErr bool + errType error + }{ + { + name: "resolve from direct value", + value: telemetryv1alpha1.ValueType{Value: "direct-value"}, + expected: []byte("direct-value"), + expectedErr: false, + }, + { + name: "resolve from undefined value", + value: telemetryv1alpha1.ValueType{ + Value: "", + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: nil, + }, + }, + expected: nil, + expectedErr: true, + errType: ErrValueOrSecretRefUndefined, + }, + { + name: "resolve from secret", + value: telemetryv1alpha1.ValueType{ + Value: "", + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ + Name: "test-secret", + Key: "test-key", + Namespace: "default", + }, + }, + }, + expected: []byte("secret-value"), + expectedErr: false, + }, + { + name: "direct value takes precedence over secret", + value: telemetryv1alpha1.ValueType{ + Value: "direct-value", + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ + Name: "test-secret", + Key: "test-key", + Namespace: "default", + }, + }, + }, + expected: []byte("direct-value"), + expectedErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := ResolveValue(ctx, client, tt.value) + if tt.expectedErr { + require.Error(t, err) + assert.True(t, errors.Is(err, tt.errType)) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expected, result) + } + }) + } +} + func TestIsFilterDefined(t *testing.T) { tests := []struct { name string diff --git a/internal/utils/test/log_pipeline_builder.go b/internal/utils/test/log_pipeline_builder.go index cf8c1f3a0c..9dba17c257 100644 --- a/internal/utils/test/log_pipeline_builder.go +++ b/internal/utils/test/log_pipeline_builder.go @@ -24,6 +24,7 @@ type LogPipelineBuilder struct { httpOutput *telemetryv1alpha1.FluentBitHTTPOutput otlpOutput *telemetryv1alpha1.OTLPOutput + oauth2 *telemetryv1alpha1.OAuth2Options customOutput string fluentBitFilters []telemetryv1alpha1.FluentBitFilter @@ -277,6 +278,29 @@ func (b *LogPipelineBuilder) WithOTLPOutput(opts ...OTLPOutputOption) *LogPipeli return b } +func (b *LogPipelineBuilder) WithOAuth2(opts ...OAuth2Option) *LogPipelineBuilder { + if b.oauth2 == nil { + b.oauth2 = &telemetryv1alpha1.OAuth2Options{} + } + + for _, opt := range opts { + opt(b.oauth2) + } + + // Set OAuth2 on the OTLP output authentication + if b.otlpOutput == nil { + b.otlpOutput = defaultOTLPOutput() + } + + if b.otlpOutput.Authentication == nil { + b.otlpOutput.Authentication = &telemetryv1alpha1.AuthenticationOptions{} + } + + b.otlpOutput.Authentication.OAuth2 = b.oauth2 + + return b +} + func (b *LogPipelineBuilder) WithCustomOutput(custom string) *LogPipelineBuilder { b.customOutput = custom return b diff --git a/internal/utils/test/metric_pipeline_builder.go b/internal/utils/test/metric_pipeline_builder.go index 5ec93f908a..0d7eab0a08 100644 --- a/internal/utils/test/metric_pipeline_builder.go +++ b/internal/utils/test/metric_pipeline_builder.go @@ -24,6 +24,7 @@ type MetricPipelineBuilder struct { inOTLP *telemetryv1alpha1.OTLPInput outOTLP *telemetryv1alpha1.OTLPOutput + oauth2 *telemetryv1alpha1.OAuth2Options transforms []telemetryv1alpha1.TransformSpec filter []telemetryv1alpha1.FilterSpec @@ -388,6 +389,25 @@ func (b *MetricPipelineBuilder) WithOTLPOutput(opts ...OTLPOutputOption) *Metric return b } +func (b *MetricPipelineBuilder) WithOAuth2(opts ...OAuth2Option) *MetricPipelineBuilder { + if b.oauth2 == nil { + b.oauth2 = &telemetryv1alpha1.OAuth2Options{} + } + + for _, opt := range opts { + opt(b.oauth2) + } + + // Set OAuth2 on the OTLP output authentication + if b.outOTLP.Authentication == nil { + b.outOTLP.Authentication = &telemetryv1alpha1.AuthenticationOptions{} + } + + b.outOTLP.Authentication.OAuth2 = b.oauth2 + + return b +} + func (b *MetricPipelineBuilder) WithTransform(transform telemetryv1alpha1.TransformSpec) *MetricPipelineBuilder { b.transforms = append(b.transforms, transform) return b diff --git a/internal/utils/test/pipeline_opts.go b/internal/utils/test/pipeline_opts.go index e80659b887..3f62462e6d 100644 --- a/internal/utils/test/pipeline_opts.go +++ b/internal/utils/test/pipeline_opts.go @@ -14,6 +14,19 @@ func OTLPEndpoint(endpoint string) OTLPOutputOption { } } +func OTLPOAuth2(oauth2Opts ...OAuth2Option) OTLPOutputOption { + return func(output *telemetryv1alpha1.OTLPOutput) { + oauth2opts := &telemetryv1alpha1.OAuth2Options{} + for _, opt := range oauth2Opts { + opt(oauth2opts) + } + + output.Authentication = &telemetryv1alpha1.AuthenticationOptions{ + OAuth2: oauth2opts, + } + } +} + func OTLPEndpointFromSecret(secretName, secretNamespace, endpointKey string) OTLPOutputOption { return func(output *telemetryv1alpha1.OTLPOutput) { output.Endpoint = telemetryv1alpha1.ValueType{ @@ -78,7 +91,8 @@ func OTLPCustomHeader(name, value, prefix string) OTLPOutputOption { } } -func OTLPClientTLSFromString(ca, cert, key string) OTLPOutputOption { +// OTLPClientMTLSFromString sets the mTLS configuration for the OTLP output +func OTLPClientMTLSFromString(ca, cert, key string) OTLPOutputOption { return func(output *telemetryv1alpha1.OTLPOutput) { output.TLS = &telemetryv1alpha1.OTLPTLS{ CA: &telemetryv1alpha1.ValueType{Value: ca}, @@ -88,12 +102,41 @@ func OTLPClientTLSFromString(ca, cert, key string) OTLPOutputOption { } } +// OTLPClientTLS sets the TLS configuration for the OTLP output (it does not include client certs) func OTLPClientTLS(tls *telemetryv1alpha1.OTLPTLS) OTLPOutputOption { return func(output *telemetryv1alpha1.OTLPOutput) { output.TLS = tls } } +func OTLPClientTLSFromString(ca string) OTLPOutputOption { + return func(output *telemetryv1alpha1.OTLPOutput) { + output.TLS = &telemetryv1alpha1.OTLPTLS{ + CA: &telemetryv1alpha1.ValueType{Value: ca}, + } + } +} + +func OTLPInsecure(insecure bool) OTLPOutputOption { + return func(output *telemetryv1alpha1.OTLPOutput) { + if output.TLS == nil { + output.TLS = &telemetryv1alpha1.OTLPTLS{} + } + + output.TLS.Insecure = insecure + } +} + +func OTLPInsecureSkipVerify(insecure bool) OTLPOutputOption { + return func(output *telemetryv1alpha1.OTLPOutput) { + if output.TLS == nil { + output.TLS = &telemetryv1alpha1.OTLPTLS{} + } + + output.TLS.InsecureSkipVerify = insecure + } +} + func OTLPProtocol(protocol string) OTLPOutputOption { return func(output *telemetryv1alpha1.OTLPOutput) { output.Protocol = protocol @@ -106,6 +149,80 @@ func OTLPEndpointPath(path string) OTLPOutputOption { } } +type OAuth2Option func(oauth2 *telemetryv1alpha1.OAuth2Options) + +func OAuth2ClientID(clientID string) OAuth2Option { + return func(oauth2 *telemetryv1alpha1.OAuth2Options) { + oauth2.ClientID = telemetryv1alpha1.ValueType{Value: clientID} + } +} + +func OAuth2ClientIDFromSecret(secretName, secretNamespace, key string) OAuth2Option { + return func(oauth2 *telemetryv1alpha1.OAuth2Options) { + oauth2.ClientID = telemetryv1alpha1.ValueType{ + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ + Name: secretName, + Namespace: secretNamespace, + Key: key, + }, + }, + } + } +} + +func OAuth2ClientSecret(clientSecret string) OAuth2Option { + return func(oauth2 *telemetryv1alpha1.OAuth2Options) { + oauth2.ClientSecret = telemetryv1alpha1.ValueType{Value: clientSecret} + } +} + +func OAuth2ClientSecretFromSecret(secretName, secretNamespace, key string) OAuth2Option { + return func(oauth2 *telemetryv1alpha1.OAuth2Options) { + oauth2.ClientSecret = telemetryv1alpha1.ValueType{ + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ + Name: secretName, + Namespace: secretNamespace, + Key: key, + }, + }, + } + } +} + +func OAuth2TokenURL(tokenURL string) OAuth2Option { + return func(oauth2 *telemetryv1alpha1.OAuth2Options) { + oauth2.TokenURL = telemetryv1alpha1.ValueType{Value: tokenURL} + } +} + +func OAuth2TokenURLFromSecret(secretName, secretNamespace, key string) OAuth2Option { + return func(oauth2 *telemetryv1alpha1.OAuth2Options) { + oauth2.TokenURL = telemetryv1alpha1.ValueType{ + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ + Name: secretName, + Namespace: secretNamespace, + Key: key, + }, + }, + } + } +} + +func OAuth2Scopes(scopes []string) OAuth2Option { + return func(oauth2 *telemetryv1alpha1.OAuth2Options) { + oauth2.Scopes = scopes + } +} + +func OAuth2Params(params map[string]string) OAuth2Option { + return func(oauth2 *telemetryv1alpha1.OAuth2Options) { + oauth2.Params = params + } +} + type HTTPOutputOption func(output *telemetryv1alpha1.FluentBitHTTPOutput) func HTTPClientTLSFromString(ca, cert, key string) HTTPOutputOption { diff --git a/internal/utils/test/trace_pipeline_builder.go b/internal/utils/test/trace_pipeline_builder.go index be5bed3dfa..2baaf5632e 100644 --- a/internal/utils/test/trace_pipeline_builder.go +++ b/internal/utils/test/trace_pipeline_builder.go @@ -20,6 +20,7 @@ type TracePipelineBuilder struct { filters []telemetryv1alpha1.FilterSpec statusConditions []metav1.Condition outOTLP *telemetryv1alpha1.OTLPOutput + oauth2 *telemetryv1alpha1.OAuth2Options } func NewTracePipelineBuilder() *TracePipelineBuilder { @@ -59,6 +60,25 @@ func (b *TracePipelineBuilder) WithOTLPOutput(opts ...OTLPOutputOption) *TracePi return b } +func (b *TracePipelineBuilder) WithOAuth2(opts ...OAuth2Option) *TracePipelineBuilder { + if b.oauth2 == nil { + b.oauth2 = &telemetryv1alpha1.OAuth2Options{} + } + + for _, opt := range opts { + opt(b.oauth2) + } + + // Set OAuth2 on the OTLP output authentication + if b.outOTLP.Authentication == nil { + b.outOTLP.Authentication = &telemetryv1alpha1.AuthenticationOptions{} + } + + b.outOTLP.Authentication.OAuth2 = b.oauth2 + + return b +} + func (b *TracePipelineBuilder) WithTransform(transform telemetryv1alpha1.TransformSpec) *TracePipelineBuilder { b.transforms = append(b.transforms, transform) return b diff --git a/internal/validators/endpoint/endpoint_validator.go b/internal/validators/endpoint/endpoint_validator.go index 83546b8ed7..532c26997d 100644 --- a/internal/validators/endpoint/endpoint_validator.go +++ b/internal/validators/endpoint/endpoint_validator.go @@ -20,6 +20,13 @@ const ( OTLPProtocolHTTP = telemetryv1alpha1.OTLPProtocolHTTP ) +type EndpointValidationParams struct { + Endpoint *telemetryv1alpha1.ValueType + Protocol string + OTLPTLS *telemetryv1alpha1.OTLPTLS + OTLPOAuth2 *telemetryv1alpha1.OAuth2Options +} + type Validator struct { Client client.Reader } @@ -28,6 +35,8 @@ var ( ErrValueResolveFailed = errors.New("failed to resolve value") ErrPortMissing = errors.New("missing port") ErrUnsupportedScheme = errors.New("missing or unsupported protocol scheme") + ErrGRPCOAuth2NoTLS = errors.New("OAuth2 requires TLS when using gRPC protocol") + ErrHTTPWithTLS = errors.New("HTTP scheme with TLS not allowed") ) type EndpointInvalidError struct { @@ -47,12 +56,12 @@ func IsEndpointInvalidError(err error) bool { return errors.As(err, &errEndpointInvalid) } -func (v *Validator) Validate(ctx context.Context, endpoint *telemetryv1alpha1.ValueType, protocol string) error { - if endpoint == nil { +func (v *Validator) Validate(ctx context.Context, params EndpointValidationParams) error { + if params.Endpoint == nil { return &EndpointInvalidError{Err: ErrValueResolveFailed} } - endpointValue, err := resolveValue(ctx, v.Client, *endpoint) + endpointValue, err := resolveValue(ctx, v.Client, *params.Endpoint) if err != nil { return err } @@ -63,21 +72,41 @@ func (v *Validator) Validate(ctx context.Context, endpoint *telemetryv1alpha1.Va return err } - if protocol == FluentdProtocolHTTP { + // early return if protocol is Fluentd => further validation is OTLP-exclusive + if params.Protocol == FluentdProtocolHTTP { return nil } var hostport = u.Host + u.Path - if err := validatePort(hostport, protocol == OTLPProtocolHTTP); err != nil { + + // port validation + if err := validatePort(hostport, params.Protocol == OTLPProtocolHTTP); err != nil { return err } - if protocol == OTLPProtocolHTTP { + // scheme validation + if params.Protocol == OTLPProtocolHTTP { if err := validateSchemeHTTP(u.Scheme); err != nil { return err } } + // OAuth2 validation + if params.OTLPOAuth2 != nil { + var validationFunc func(string, *telemetryv1alpha1.OTLPTLS) error + + switch params.Protocol { + case OTLPProtocolGRPC: + validationFunc = validateGRPCWithOAuth2 + case OTLPProtocolHTTP: + validationFunc = validateHTTPWithOAuth2 + } + + if err := validationFunc(u.Scheme, params.OTLPTLS); err != nil { + return err + } + } + return nil } @@ -150,3 +179,34 @@ func validateSchemeHTTP(scheme string) error { return nil } + +func validateGRPCWithOAuth2(scheme string, tls *telemetryv1alpha1.OTLPTLS) error { + // Insecure TLS config + if tls != nil && tls.Insecure { + return &EndpointInvalidError{Err: ErrGRPCOAuth2NoTLS} + } + + // HTTP scheme: invalid in all cases + if scheme == "http" { + return &EndpointInvalidError{Err: errors.New(ErrGRPCOAuth2NoTLS.Error() + ": HTTP scheme not allowed")} + } + + return nil +} + +func validateHTTPWithOAuth2(scheme string, tls *telemetryv1alpha1.OTLPTLS) error { + // HTTP scheme with TLS + if scheme == "http" && isTLSConfigured(tls) { + return &EndpointInvalidError{Err: ErrHTTPWithTLS} + } + + return nil +} + +func isTLSConfigured(tls *telemetryv1alpha1.OTLPTLS) bool { + if tls == nil || tls.Insecure { + return false + } + + return tls.CA != nil || tls.Cert != nil || tls.Key != nil +} diff --git a/internal/validators/endpoint/endpoint_validator_test.go b/internal/validators/endpoint/endpoint_validator_test.go index ef59cf6288..0d4050f0d2 100644 --- a/internal/validators/endpoint/endpoint_validator_test.go +++ b/internal/validators/endpoint/endpoint_validator_test.go @@ -20,6 +20,8 @@ const ( errMsgPortInvalidSegmented = "address %s: too many colons in address" errMsgPortMissing = "missing port" errMsgUnsupportedScheme = "missing or unsupported protocol scheme" + errMsgGRPCOAuth2NoTLS = "OAuth2 requires TLS when using gRPC protocol" + errMsgHTTPWithTLS = "HTTP scheme with TLS not allowed" ) var testScenarios = []struct { @@ -359,8 +361,10 @@ func TestOTLPGRPCEndpoints(t *testing.T) { err := validator.Validate( t.Context(), - &telemetryv1alpha1.ValueType{Value: test.endpoint}, - OTLPProtocolGRPC) + EndpointValidationParams{ + Endpoint: &telemetryv1alpha1.ValueType{Value: test.endpoint}, + Protocol: OTLPProtocolGRPC, + }) switch { case test.errOTLPGRPC != nil && test.errMsgOTLPGRPC != "": @@ -386,8 +390,10 @@ func TestOTLPHttpEndpoints(t *testing.T) { err := validator.Validate( t.Context(), - &telemetryv1alpha1.ValueType{Value: test.endpoint}, - OTLPProtocolHTTP) + EndpointValidationParams{ + Endpoint: &telemetryv1alpha1.ValueType{Value: test.endpoint}, + Protocol: OTLPProtocolHTTP, + }) switch { case test.errOTLPHTTP != nil && test.errMsgOTLPHTTP != "": @@ -414,8 +420,10 @@ func TestFluentdHttpEndpoints(t *testing.T) { err := validator.Validate( t.Context(), - &telemetryv1alpha1.ValueType{Value: test.endpoint}, - FluentdProtocolHTTP) + EndpointValidationParams{ + Endpoint: &telemetryv1alpha1.ValueType{Value: test.endpoint}, + Protocol: FluentdProtocolHTTP, + }) switch { case test.errFluentdHTTP != nil && test.errMsgFluentdHTTP != "": @@ -438,8 +446,8 @@ func TestMissingEndpoint(t *testing.T) { Client: fakeClient, } - errNil := validator.Validate(t.Context(), nil, OTLPProtocolGRPC) - errNoValue := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{}, OTLPProtocolGRPC) + errNil := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: nil, Protocol: OTLPProtocolGRPC}) + errNoValue := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{}, Protocol: OTLPProtocolGRPC}) require.True(t, errors.Is(errNil, ErrValueResolveFailed)) require.EqualError(t, errNil, errMsgEndpointResolveFailed) @@ -464,24 +472,24 @@ func TestEndpointValueFromValid(t *testing.T) { Client: fakeClient, } - errGRPC := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + errGRPC := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "test", Namespace: "default", Key: "endpoint", - }}}, OTLPProtocolGRPC) - errHTTP := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + }}}, Protocol: OTLPProtocolGRPC}) + errHTTP := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "test", Namespace: "default", Key: "endpoint", - }}}, OTLPProtocolHTTP) - errFluentd := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + }}}, Protocol: OTLPProtocolHTTP}) + errFluentd := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "test", Namespace: "default", Key: "endpoint", - }}}, FluentdProtocolHTTP) + }}}, Protocol: FluentdProtocolHTTP}) require.NoError(t, errGRPC) require.NoError(t, errHTTP) @@ -505,24 +513,24 @@ func TestEndpointValueFromInvalid(t *testing.T) { Client: fakeClient, } - errGRPC := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + errGRPC := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "test", Namespace: "default", Key: "endpoint", - }}}, OTLPProtocolGRPC) - errHTTP := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + }}}, Protocol: OTLPProtocolGRPC}) + errHTTP := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "test", Namespace: "default", Key: "endpoint", - }}}, OTLPProtocolGRPC) - errFluentd := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + }}}, Protocol: OTLPProtocolGRPC}) + errFluentd := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "test", Namespace: "default", Key: "endpoint", - }}}, FluentdProtocolHTTP) + }}}, Protocol: FluentdProtocolHTTP}) require.True(t, IsEndpointInvalidError(errGRPC)) require.EqualError(t, errGRPC, fmt.Sprintf(errMsgEndpointInvalid, invalidEndpoint)) @@ -549,24 +557,24 @@ func TestEndpointValueFromMissing(t *testing.T) { Client: fakeClient, } - errGRPC := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + errGRPC := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "unknown", Namespace: "default", Key: "endpoint", - }}}, OTLPProtocolGRPC) - errHTTP := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + }}}, Protocol: OTLPProtocolGRPC}) + errHTTP := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "unknown", Namespace: "default", Key: "endpoint", - }}}, OTLPProtocolHTTP) - errFluentd := validator.Validate(t.Context(), &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ + }}}, Protocol: OTLPProtocolHTTP}) + errFluentd := validator.Validate(t.Context(), EndpointValidationParams{Endpoint: &telemetryv1alpha1.ValueType{ValueFrom: &telemetryv1alpha1.ValueFromSource{ SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ Name: "unknown", Namespace: "default", Key: "endpoint", - }}}, FluentdProtocolHTTP) + }}}, Protocol: FluentdProtocolHTTP}) require.True(t, errors.Is(errGRPC, ErrValueResolveFailed)) require.EqualError(t, errGRPC, errMsgEndpointResolveFailed) @@ -575,3 +583,176 @@ func TestEndpointValueFromMissing(t *testing.T) { require.True(t, errors.Is(errFluentd, ErrValueResolveFailed)) require.EqualError(t, errFluentd, errMsgEndpointResolveFailed) } + +var testScenariosWithOAuth2 = []struct { + name string + endpoint string + tls *telemetryv1alpha1.OTLPTLS + + errMsgOTLPGRPC string + errMsgOTLPHTTP string +}{ + // without TLS configuration + { + name: "http scheme without TLS", + endpoint: "http://example.com:8080", + tls: nil, + errMsgOTLPGRPC: errMsgGRPCOAuth2NoTLS + ": HTTP scheme not allowed", + errMsgOTLPHTTP: "", + }, + { + name: "https scheme without TLS", + endpoint: "https://example.com:8080", + tls: nil, + errMsgOTLPGRPC: "", + errMsgOTLPHTTP: "", + }, + { + name: "no scheme without TLS", + endpoint: "example.com:8080", + tls: nil, + errMsgOTLPGRPC: "", + errMsgOTLPHTTP: errMsgUnsupportedScheme, + }, + + // with TLS configuration + { + name: "http scheme with TLS", + endpoint: "http://example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + CA: &telemetryv1alpha1.ValueType{Value: "ca-data"}, + }, + errMsgOTLPGRPC: errMsgGRPCOAuth2NoTLS + ": HTTP scheme not allowed", + errMsgOTLPHTTP: errMsgHTTPWithTLS, + }, + { + name: "https scheme with TLS", + endpoint: "https://example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + CA: &telemetryv1alpha1.ValueType{Value: "ca-data"}, + }, + errMsgOTLPGRPC: "", + errMsgOTLPHTTP: "", + }, + { + name: "no scheme with TLS", + endpoint: "example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + CA: &telemetryv1alpha1.ValueType{Value: "ca-data"}, + }, + errMsgOTLPGRPC: "", + errMsgOTLPHTTP: errMsgUnsupportedScheme, + }, + + // with insecureSkipVerify + { + name: "http scheme with TLS insecureSkipVerify", + endpoint: "http://example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + InsecureSkipVerify: true, + }, + errMsgOTLPGRPC: errMsgGRPCOAuth2NoTLS + ": HTTP scheme not allowed", + errMsgOTLPHTTP: "", + }, + { + name: "https scheme with TLS insecureSkipVerify", + endpoint: "https://example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + InsecureSkipVerify: true, + }, + errMsgOTLPGRPC: "", + errMsgOTLPHTTP: "", + }, + { + name: "no scheme with TLS insecureSkipVerify", + endpoint: "example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + InsecureSkipVerify: true, + }, + errMsgOTLPGRPC: "", + errMsgOTLPHTTP: errMsgUnsupportedScheme, + }, + + // with insecure + { + name: "http scheme with TLS insecure", + endpoint: "http://example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + Insecure: true, + }, + errMsgOTLPGRPC: errMsgGRPCOAuth2NoTLS, + errMsgOTLPHTTP: "", + }, + { + name: "https scheme with TLS insecure", + endpoint: "https://example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + Insecure: true, + }, + errMsgOTLPGRPC: errMsgGRPCOAuth2NoTLS, + errMsgOTLPHTTP: "", + }, + { + name: "no scheme with TLS insecure", + endpoint: "example.com:8080", + tls: &telemetryv1alpha1.OTLPTLS{ + Insecure: true, + }, + errMsgOTLPGRPC: errMsgGRPCOAuth2NoTLS, + errMsgOTLPHTTP: errMsgUnsupportedScheme, + }, +} + +func TestOTLPGRPCEndpointsWithOAuth2(t *testing.T) { + for _, test := range testScenariosWithOAuth2 { + t.Run(test.name, func(t *testing.T) { + fakeClient := fake.NewClientBuilder().Build() + validator := Validator{ + Client: fakeClient, + } + + err := validator.Validate( + t.Context(), + EndpointValidationParams{ + Endpoint: &telemetryv1alpha1.ValueType{Value: test.endpoint}, + Protocol: OTLPProtocolGRPC, + OTLPOAuth2: &telemetryv1alpha1.OAuth2Options{}, + OTLPTLS: test.tls, + }) + + if test.errMsgOTLPGRPC != "" { + require.True(t, IsEndpointInvalidError(err)) + require.EqualError(t, err, test.errMsgOTLPGRPC) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestOTLPHTTPEndpointsWithOAuth2(t *testing.T) { + for _, test := range testScenariosWithOAuth2 { + t.Run(test.name, func(t *testing.T) { + fakeClient := fake.NewClientBuilder().Build() + validator := Validator{ + Client: fakeClient, + } + + err := validator.Validate( + t.Context(), + EndpointValidationParams{ + Endpoint: &telemetryv1alpha1.ValueType{Value: test.endpoint}, + Protocol: OTLPProtocolHTTP, + OTLPOAuth2: &telemetryv1alpha1.OAuth2Options{}, + OTLPTLS: test.tls, + }) + + if test.errMsgOTLPHTTP != "" { + require.True(t, IsEndpointInvalidError(err)) + require.EqualError(t, err, test.errMsgOTLPHTTP) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/internal/validators/secretref/secret_ref.go b/internal/validators/secretref/secret_ref.go index 454109d632..dd43e836cc 100644 --- a/internal/validators/secretref/secret_ref.go +++ b/internal/validators/secretref/secret_ref.go @@ -153,15 +153,19 @@ func getSecretRefsInOTLPOutput(otlpOut *telemetryv1alpha1.OTLPOutput) []telemetr refs = appendIfSecretRef(refs, &otlpOut.Authentication.Basic.Password) } + if otlpOut.Authentication != nil && otlpOut.Authentication.OAuth2 != nil { + refs = appendIfSecretRef(refs, &otlpOut.Authentication.OAuth2.TokenURL) + refs = appendIfSecretRef(refs, &otlpOut.Authentication.OAuth2.ClientID) + refs = appendIfSecretRef(refs, &otlpOut.Authentication.OAuth2.ClientSecret) + } + for _, header := range otlpOut.Headers { refs = appendIfSecretRef(refs, &header.ValueType) } if otlpOut.TLS != nil && !otlpOut.TLS.Insecure { refs = appendIfSecretRef(refs, otlpOut.TLS.CA) - refs = appendIfSecretRef(refs, otlpOut.TLS.Cert) - refs = appendIfSecretRef(refs, otlpOut.TLS.Key) } diff --git a/internal/validators/secretref/secret_ref_test.go b/internal/validators/secretref/secret_ref_test.go index 4b052c435b..2677a9cbd1 100644 --- a/internal/validators/secretref/secret_ref_test.go +++ b/internal/validators/secretref/secret_ref_test.go @@ -288,6 +288,49 @@ func TestTracePipeline_GetSecretRefs(t *testing.T) { {Name: "secret-3", Namespace: "default"}, }, }, + { + name: "oauth2", + pipelineName: "test-pipeline", + given: &telemetryv1alpha1.OTLPOutput{ + Authentication: &telemetryv1alpha1.AuthenticationOptions{ + OAuth2: &telemetryv1alpha1.OAuth2Options{ + TokenURL: telemetryv1alpha1.ValueType{ + Value: "", + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ + Name: "secret-1", + Namespace: "default", + Key: "token-url", + }}, + }, + ClientID: telemetryv1alpha1.ValueType{ + Value: "", + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ + Name: "secret-2", + Namespace: "default", + Key: "client-id", + }}, + }, + ClientSecret: telemetryv1alpha1.ValueType{ + Value: "", + ValueFrom: &telemetryv1alpha1.ValueFromSource{ + SecretKeyRef: &telemetryv1alpha1.SecretKeyRef{ + Name: "secret-3", + Namespace: "default", + Key: "client-secret", + }}, + }, + }, + }, + }, + + expected: []telemetryv1alpha1.SecretKeyRef{ + {Name: "secret-1", Namespace: "default", Key: "token-url"}, + {Name: "secret-2", Namespace: "default", Key: "client-id"}, + {Name: "secret-3", Namespace: "default", Key: "client-secret"}, + }, + }, } for _, test := range tests { diff --git a/internal/validators/tlscert/tls_cert_validator.go b/internal/validators/tlscert/tls_cert_validator.go index 3cf689ff05..785e2ab3ca 100644 --- a/internal/validators/tlscert/tls_cert_validator.go +++ b/internal/validators/tlscert/tls_cert_validator.go @@ -36,7 +36,7 @@ var ( ErrCertIsNotCA = errors.New("not a CA certificate") ) -type TLSBundle struct { +type TLSValidationParams struct { Cert *telemetryv1alpha1.ValueType Key *telemetryv1alpha1.ValueType CA *telemetryv1alpha1.ValueType @@ -99,7 +99,7 @@ func New(client client.Client) *Validator { } } -func (v *Validator) Validate(ctx context.Context, tls TLSBundle) error { +func (v *Validator) Validate(ctx context.Context, tls TLSValidationParams) error { // 1. Values Resolution if (tls.Cert == nil) != (tls.Key == nil) { return ErrMissingCertKeyPair @@ -245,7 +245,7 @@ func validateCA(ca *x509.Certificate, now time.Time) error { return nil } -func resolveValues(ctx context.Context, c client.Reader, tls TLSBundle) ([]byte, []byte, []byte, error) { +func resolveValues(ctx context.Context, c client.Reader, tls TLSValidationParams) ([]byte, []byte, []byte, error) { var certPEM, keyPEM, caPEM []byte var err error diff --git a/internal/validators/tlscert/tls_cert_validator_test.go b/internal/validators/tlscert/tls_cert_validator_test.go index b8932d0da3..53a8c116ff 100644 --- a/internal/validators/tlscert/tls_cert_validator_test.go +++ b/internal/validators/tlscert/tls_cert_validator_test.go @@ -95,7 +95,7 @@ func TestMissingCert(t *testing.T) { now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(defaultCaData)}, }) @@ -110,7 +110,7 @@ func TestMissingKey(t *testing.T) { now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, CA: &telemetryv1alpha1.ValueType{Value: string(defaultCaData)}, }) @@ -125,7 +125,7 @@ func TestMissingCA(t *testing.T) { now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, }) @@ -140,7 +140,7 @@ func TestMissingCertAndKey(t *testing.T) { now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ CA: &telemetryv1alpha1.ValueType{Value: string(defaultCaData)}, }) require.NoError(t, err) @@ -154,7 +154,7 @@ func TestMissingAll(t *testing.T) { now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{}) + err := validator.Validate(t.Context(), TLSValidationParams{}) require.NoError(t, err) } @@ -166,7 +166,7 @@ func TestExpiredCertificate(t *testing.T) { now: func() time.Time { return oneDayAfterExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(defaultCaData)}, @@ -214,7 +214,7 @@ func TestAboutToExpireCertificate(t *testing.T) { now: func() time.Time { return test.now }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(defaultCaData)}, @@ -244,7 +244,7 @@ func TestValidCertificatesAndPrivateKey(t *testing.T) { now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(defaultCaData)}, @@ -274,7 +274,7 @@ WxZIBPi0z6MoiZxVKSY8EBeVYCHWS9A2l1J6gAHptihe7y1j8I2ffS now: func() time.Time { return certExpiry.Add(-24 * time.Hour) }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(certData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(defaultCaData)}, @@ -303,7 +303,7 @@ ga5H3f7hUBINasQIdOGEAy3clqCBpLj2eUMXHHNxVsVGBnJOEqckn6fg6pcHnhmK fakeClient := fake.NewClientBuilder().Build() validator := New(fakeClient) - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(keyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(defaultCaData)}, @@ -335,7 +335,7 @@ WWL1dEpm9rYQvcflxENRpp9SpyG2bJliRexjmHYwFg== now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(caData)}, @@ -351,7 +351,7 @@ func TestExpiredCA(t *testing.T) { now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(pastCaData)}, @@ -399,7 +399,7 @@ func TestAboutToExpireCA(t *testing.T) { now: func() time.Time { return test.now }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(pastCaData)}, @@ -461,7 +461,7 @@ rZ3xPLf7G+fObmeO7XuIoDfJHH6HDrdhhWi3F918KQ== now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(caData)}, @@ -477,7 +477,7 @@ func TestEmptyCA(t *testing.T) { now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(defaultCertData)}, Key: &telemetryv1alpha1.ValueType{Value: string(defaultKeyData)}, CA: &telemetryv1alpha1.ValueType{Value: string([]byte(``))}, @@ -493,7 +493,7 @@ func TestSanitizeTLSSecretWithEscapedNewLine(t *testing.T) { fakeClient := fake.NewClientBuilder().Build() validator := New(fakeClient) - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: certData}, Key: &telemetryv1alpha1.ValueType{Value: keyData}, CA: &telemetryv1alpha1.ValueType{Value: caData}, @@ -509,7 +509,7 @@ func TestSanitizeValidTLSSecret(t *testing.T) { fakeClient := fake.NewClientBuilder().Build() validator := New(fakeClient) - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: certData}, Key: &telemetryv1alpha1.ValueType{Value: keyData}, CA: &telemetryv1alpha1.ValueType{Value: caData}, @@ -670,7 +670,7 @@ func TestResolveValue(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { tt := test - tlsConfig := TLSBundle{ + tlsConfig := TLSValidationParams{ Cert: &tt.inputCert, Key: &tt.inputKey, CA: &tt.inputCa, @@ -694,7 +694,7 @@ func TestInvalidCertificateKeyPair(t *testing.T) { fakeClient := fake.NewClientBuilder().Build() validator := New(fakeClient) - err = validator.Validate(t.Context(), TLSBundle{ + err = validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: certData}, Key: &telemetryv1alpha1.ValueType{Value: keyData}, CA: &telemetryv1alpha1.ValueType{Value: caData}, @@ -716,7 +716,7 @@ func TestInvalidCertPair_WithExpiredCert(t *testing.T) { fakeClient := fake.NewClientBuilder().Build() validator := New(fakeClient) - err = validator.Validate(t.Context(), TLSBundle{ + err = validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: certData}, Key: &telemetryv1alpha1.ValueType{Value: keyData}, CA: &telemetryv1alpha1.ValueType{Value: caData}, @@ -783,7 +783,7 @@ hhEW5poLfUe8MIvCQoO1GrDpnNZOn7tMjg== now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(certData)}, Key: &telemetryv1alpha1.ValueType{Value: string(keyData)}, CA: &telemetryv1alpha1.ValueType{Value: string(caData)}, @@ -822,7 +822,7 @@ in/teDa5g0ku0oO9LfLphbvaTUDhscko4g== now: func() time.Time { return oneMonthBeforeExpiry }, } - err := validator.Validate(t.Context(), TLSBundle{ + err := validator.Validate(t.Context(), TLSValidationParams{ Cert: &telemetryv1alpha1.ValueType{Value: string(certData)}, Key: &telemetryv1alpha1.ValueType{Value: string(keyData)}, }) diff --git a/test/e2e/logs/agent/instrumentation_scope_test.go b/test/e2e/logs/agent/instrumentation_scope_test.go index a811a00dee..fd159cab20 100644 --- a/test/e2e/logs/agent/instrumentation_scope_test.go +++ b/test/e2e/logs/agent/instrumentation_scope_test.go @@ -34,7 +34,7 @@ func TestInstrumentationScope(t *testing.T) { WithName(pipelineName). WithApplicationInput(true, []testutils.ExtendedNamespaceSelectorOptions{testutils.ExtIncludeNamespaces(genNs)}...). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/agent/severity_parser_test.go b/test/e2e/logs/agent/severity_parser_test.go index 323510ba7c..43d5b9e7bc 100644 --- a/test/e2e/logs/agent/severity_parser_test.go +++ b/test/e2e/logs/agent/severity_parser_test.go @@ -48,7 +48,7 @@ func TestSeverityParser(t *testing.T) { WithName(pipelineName). WithApplicationInput(true, []testutils.ExtendedNamespaceSelectorOptions{testutils.ExtIncludeNamespaces(genNs)}...). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/agent/trace_parser_test.go b/test/e2e/logs/agent/trace_parser_test.go index 575f4b71df..7851dc5ca5 100644 --- a/test/e2e/logs/agent/trace_parser_test.go +++ b/test/e2e/logs/agent/trace_parser_test.go @@ -56,7 +56,7 @@ func TestTraceParser(t *testing.T) { WithName(pipelineName). WithApplicationInput(true, []testutils.ExtendedNamespaceSelectorOptions{testutils.ExtIncludeNamespaces(genNs)}...). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/gateway/enrichment_values_empty_test.go b/test/e2e/logs/gateway/enrichment_values_empty_test.go index eb4d96118c..34882fb8e9 100644 --- a/test/e2e/logs/gateway/enrichment_values_empty_test.go +++ b/test/e2e/logs/gateway/enrichment_values_empty_test.go @@ -32,7 +32,7 @@ func TestEnrichmentValuesEmpty(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithIncludeNamespaces(genNs). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() // All attributes in the enrichment flow are set to empty values diff --git a/test/e2e/logs/gateway/enrichment_values_predefined_test.go b/test/e2e/logs/gateway/enrichment_values_predefined_test.go index 1f9f6af12f..7424498f2e 100644 --- a/test/e2e/logs/gateway/enrichment_values_predefined_test.go +++ b/test/e2e/logs/gateway/enrichment_values_predefined_test.go @@ -32,7 +32,7 @@ func TestEnrichmentValuesPredefined(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithIncludeNamespaces(genNs). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() // All attributes in the enrichment flow are set to predefined values diff --git a/test/e2e/logs/misc/mtls_cert_key_pair_dont_match_test.go b/test/e2e/logs/misc/mtls_cert_key_pair_dont_match_test.go index c10963da82..c5c69b33ad 100644 --- a/test/e2e/logs/misc/mtls_cert_key_pair_dont_match_test.go +++ b/test/e2e/logs/misc/mtls_cert_key_pair_dont_match_test.go @@ -19,7 +19,7 @@ import ( ) func TestMTLSCertKeyDontMatch_OTel(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelLogsMisc) + suite.RegisterTestCase(t, suite.LabelLogsMisc, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -33,13 +33,13 @@ func TestMTLSCertKeyDontMatch_OTel(t *testing.T) { _, clientCertsCreatedAgain, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithTLS(*serverCertsDefault)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithMTLS(*serverCertsDefault)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCertsDefault.CaCertPem.String(), clientCertsDefault.ClientCertPem.String(), clientCertsCreatedAgain.ClientKeyPem.String(), // Use different key @@ -88,7 +88,7 @@ func TestMTLSCertKeyDontMatch_FluentBit(t *testing.T) { _, clientCertsCreatedAgain, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithTLS(*serverCertsDefault)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithMTLS(*serverCertsDefault)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). diff --git a/test/e2e/logs/misc/mtls_expired_cert_test.go b/test/e2e/logs/misc/mtls_expired_cert_test.go index ce8a47feff..cb1e28e21e 100644 --- a/test/e2e/logs/misc/mtls_expired_cert_test.go +++ b/test/e2e/logs/misc/mtls_expired_cert_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSExpiredCert_OTel(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelLogsMisc) + suite.RegisterTestCase(t, suite.LabelLogsMisc, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSExpiredCert_OTel(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithTLS(*expiredServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithMTLS(*expiredServerCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( expiredClientCerts.CaCertPem.String(), expiredClientCerts.ClientCertPem.String(), expiredClientCerts.ClientKeyPem.String(), @@ -84,7 +84,7 @@ func TestMTLSExpiredCert_FluentBit(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithTLS(*expiredServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithMTLS(*expiredServerCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). diff --git a/test/e2e/logs/misc/mtls_invalid_ca_test.go b/test/e2e/logs/misc/mtls_invalid_ca_test.go index 182f2d45fa..673d213d16 100644 --- a/test/e2e/logs/misc/mtls_invalid_ca_test.go +++ b/test/e2e/logs/misc/mtls_invalid_ca_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSInvalidCA_OTel(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelLogsMisc) + suite.RegisterTestCase(t, suite.LabelLogsMisc, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSInvalidCA_OTel(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithTLS(*invalidServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithMTLS(*invalidServerCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( invalidClientCerts.CaCertPem.String(), invalidClientCerts.ClientCertPem.String(), invalidClientCerts.ClientKeyPem.String(), @@ -84,7 +84,7 @@ func TestMTLSInvalidCA_FluentBit(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithTLS(*invalidServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithMTLS(*invalidServerCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). diff --git a/test/e2e/logs/misc/mtls_invalid_cert_test.go b/test/e2e/logs/misc/mtls_invalid_cert_test.go index 0b58996e49..162f45aa1c 100644 --- a/test/e2e/logs/misc/mtls_invalid_cert_test.go +++ b/test/e2e/logs/misc/mtls_invalid_cert_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSInvalidCert_OTel(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelLogsMisc) + suite.RegisterTestCase(t, suite.LabelLogsMisc, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSInvalidCert_OTel(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithTLS(*invalidServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithMTLS(*invalidServerCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( invalidClientCerts.CaCertPem.String(), invalidClientCerts.ClientCertPem.String(), invalidClientCerts.ClientKeyPem.String(), @@ -84,7 +84,7 @@ func TestMTLSInvalidCert_FluentBit(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithTLS(*invalidServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithMTLS(*invalidServerCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). diff --git a/test/e2e/logs/misc/reject_creation_test.go b/test/e2e/logs/misc/reject_creation_test.go index 8f03d10bbe..0ee3c85985 100644 --- a/test/e2e/logs/misc/reject_creation_test.go +++ b/test/e2e/logs/misc/reject_creation_test.go @@ -27,6 +27,7 @@ func TestRejectLogPipelineCreation(t *testing.T) { var backenEndpoint = backendHost + ":" + strconv.Itoa(backendPort) tests := []struct { + name string pipeline telemetryv1alpha1.LogPipeline errorMsg string field string @@ -35,20 +36,16 @@ func TestRejectLogPipelineCreation(t *testing.T) { }{ // output general { + name: "no-output", pipeline: telemetryv1alpha1.LogPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "no-output", - }, Spec: telemetryv1alpha1.LogPipelineSpec{}, }, errorMsg: "Exactly one output out of 'custom', 'http' or 'otlp' must be defined", field: "spec.output", }, { + name: "valuefrom-accepts-only-one-option", pipeline: telemetryv1alpha1.LogPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "valuefrom-accepts-only-one-option", - }, Spec: telemetryv1alpha1.LogPipelineSpec{ Output: telemetryv1alpha1.LogPipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -70,10 +67,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint", }, { + name: "secretkeyref-requires-key", pipeline: telemetryv1alpha1.LogPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-key", - }, Spec: telemetryv1alpha1.LogPipelineSpec{ Output: telemetryv1alpha1.LogPipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -93,10 +88,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint.valueFrom.secretKeyRef.key", }, { + name: "secretkeyref-requires-namespace", pipeline: telemetryv1alpha1.LogPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-namespace", - }, Spec: telemetryv1alpha1.LogPipelineSpec{ Output: telemetryv1alpha1.LogPipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -116,10 +109,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint.valueFrom.secretKeyRef.namespace", }, { + name: "secretkeyref-requires-name", pipeline: telemetryv1alpha1.LogPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-name", - }, Spec: telemetryv1alpha1.LogPipelineSpec{ Output: telemetryv1alpha1.LogPipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -140,8 +131,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { }, // otlp output { + name: "otlp-output-with-default-proto-and-path", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-output-with-default-proto-and-path"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPEndpointPath("/v1/dummy"), @@ -151,8 +142,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp", }, { + name: "otlp-output-with-grpc-proto-and-path", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-output-with-grpc-proto-and-path"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPEndpointPath("/v1/dummy"), @@ -163,8 +154,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp", }, { + name: "otlp-output-with-non-valid-proto", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-output-with-non-valid-proto"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPProtocol("icke"), @@ -175,8 +166,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp.protocol", }, { + name: "otlp-output-basic-auth-secretref-missing-password-key", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-output-basic-auth-secretref-missing-password-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPBasicAuthFromSecret("name", "namespace", "user", ""), @@ -186,8 +177,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.key", }, { + name: "otlp-output-basic-auth-secretref-missing-user-key", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-output-basic-auth-secretref-missing-user-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPBasicAuthFromSecret("name", "namespace", "", "password"), @@ -197,8 +188,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.key", }, { + name: "otlp-output-tls-missing-key", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-output-tls-missing-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ @@ -211,8 +202,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.otlp.tls", }, { + name: "otlp-output-tls-missing-cert", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-output-tls-missing-cert"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ @@ -224,10 +215,56 @@ func TestRejectLogPipelineCreation(t *testing.T) { errorMsg: "Can define either both 'cert' and 'key', or neither", field: "spec.output.otlp.tls", }, - // otlp input { + name: "otlp-output-oauth2-invalid-token-url", + pipeline: testutils.NewLogPipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2ClientID("clientid"), + testutils.OAuth2TokenURL("../not-a-url"), + ), + ). + Build(), + errorMsg: "Invalid value: \"object\": 'tokenURL' must be a valid URL", + field: "spec.output.otlp.authentication.oauth2.tokenURL", + }, + { + name: "otlp-output-oauth2-missing-client-id", + pipeline: testutils.NewLogPipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2TokenURL("https://auth.example.com/token"), + ), + ). + Build(), + errorMsg: "Invalid value: \"object\": no such key: value evaluating rule: 'clientID' missing", + field: "spec.output.otlp.authentication.oauth2.clientID", + }, + { + name: "otlp-output-oauth2-insecure", + pipeline: testutils.NewLogPipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientID("clientid"), + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2TokenURL("https://auth.example.com/token"), + ), + testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ + Insecure: true, + }), + ). + Build(), + errorMsg: "OAuth2 authentication requires TLS when using gRPC protocol", + field: "spec.output.otlp", + }, + { + name: "otlp-input-namespaces-not-exclusive", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-input-namespaces-not-exclusive"). WithOTLPInput(true, testutils.ExcludeNamespaces("ns1"), testutils.IncludeNamespaces("ns2"), @@ -238,8 +275,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.input.otlp.namespaces", }, { + name: "otlp-input-namespaces-include-invalid", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-input-namespaces-include-invalid"). WithOTLPInput(true, testutils.IncludeNamespaces("Test"), ). @@ -249,8 +286,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.input.otlp.namespaces.include[0]", }, { + name: "otlp-input-namespaces-include-too-long", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-input-namespaces-include-too-long"). WithOTLPInput(true, testutils.IncludeNamespaces(veryLongString), ). @@ -261,8 +298,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { causes: 2, }, { + name: "otlp-input-namespaces-exclude-invalid", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-input-namespaces-exclude-invalid"). WithOTLPInput(true, testutils.ExcludeNamespaces("Test"), ). @@ -272,8 +309,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.input.otlp.namespaces.exclude[0]", }, { + name: "otlp-input-namespaces-exclude-too-long", pipeline: testutils.NewLogPipelineBuilder(). - WithName("otlp-input-namespaces-exclude-too-long"). WithOTLPInput(true, testutils.ExcludeNamespaces(veryLongString), ). @@ -285,8 +322,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { }, // http output { + name: "http-output-tls-missing-key", pipeline: testutils.NewLogPipelineBuilder(). - WithName("http-output-tls-missing-key"). WithHTTPOutput( testutils.HTTPHost(backendHost), testutils.HTTPPort(backendPort), @@ -299,8 +336,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.http.tls", }, { + name: "http-output-tls-missing-cert", pipeline: testutils.NewLogPipelineBuilder(). - WithName("http-output-tls-missing-cert"). WithHTTPOutput( testutils.HTTPHost(backendHost), testutils.HTTPPort(backendPort), @@ -313,6 +350,7 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output.http.tls", }, { + name: "http-output-uri-wrong-pattern", pipeline: telemetryv1alpha1.LogPipeline{ ObjectMeta: metav1.ObjectMeta{ Name: "http-output-uri-wrong-pattern", @@ -331,8 +369,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { }, // application input { + name: "application-input-namespaces-exclude-system-not-exclusive", pipeline: testutils.NewLogPipelineBuilder(). - WithName("application-input-namespaces-include-exclude-not-exclusive"). WithApplicationInput(true). WithIncludeNamespaces("ns1"). WithExcludeNamespaces("ns2"). @@ -342,8 +380,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.input.application.namespaces", }, { + name: "application-input-namespaces-include-exclude-not-exclusive", pipeline: testutils.NewLogPipelineBuilder(). - WithName("application-input-namespaces-include-system-not-exclusive"). WithApplicationInput(true). WithIncludeNamespaces("ns1"). WithSystemNamespaces(true). @@ -353,8 +391,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.input.application.namespaces", }, { + name: "application-input-containers-not-exclusive", pipeline: testutils.NewLogPipelineBuilder(). - WithName("application-input-containers-not-exclusive"). WithApplicationInput(true). WithIncludeContainers("c1"). WithExcludeContainers("c2"). @@ -364,8 +402,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.input.application.containers", }, { + name: "application-input-namespaces-include-invalid", pipeline: testutils.NewLogPipelineBuilder(). - WithName("application-input-namespaces-include-invalid"). WithApplicationInput(true). WithIncludeNamespaces("*"). WithOTLPOutput(). @@ -374,8 +412,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.input.application.namespaces.include[0]", }, { + name: "application-input-namespaces-include-too-long", pipeline: testutils.NewLogPipelineBuilder(). - WithName("application-input-namespaces-include-too-long"). WithApplicationInput(true). WithIncludeNamespaces(veryLongString). WithOTLPOutput(). @@ -385,8 +423,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { causes: 2, }, { + name: "application-input-namespaces-exclude-invalid", pipeline: testutils.NewLogPipelineBuilder(). - WithName("application-input-namespaces-exclude-invalid"). WithApplicationInput(true). WithExcludeNamespaces("a*a"). WithOTLPOutput(). @@ -395,8 +433,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.input.application.namespaces.exclude[0]", }, { + name: "application-input-namespaces-exclude-too-long", pipeline: testutils.NewLogPipelineBuilder(). - WithName("application-input-namespaces-exclude-too-long"). WithApplicationInput(true). WithExcludeNamespaces(veryLongString). WithOTLPOutput(). @@ -407,8 +445,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { }, // files validation { + name: "files-name-required", pipeline: testutils.NewLogPipelineBuilder(). - WithName("files-name-required"). WithFile("", "icke"). WithHTTPOutput(). Build(), @@ -416,8 +454,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.files[0].name", }, { + name: "files-content-required", pipeline: testutils.NewLogPipelineBuilder(). - WithName("files-content-required"). WithFile("file1", ""). WithHTTPOutput(). Build(), @@ -426,8 +464,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { }, // variables validation { + name: "variables-name-required", pipeline: testutils.NewLogPipelineBuilder(). - WithName("variables-name-required"). WithVariable("", "secName", "secNs", "secKey"). WithHTTPOutput(). Build(), @@ -435,6 +473,7 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.variables[0].name", }, { + name: "variables-valuefrom-required", pipeline: telemetryv1alpha1.LogPipeline{ ObjectMeta: metav1.ObjectMeta{ Name: "variables-valuefrom-required", @@ -456,8 +495,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { }, // legacy validations { + name: "multiple-outputs", pipeline: testutils.NewLogPipelineBuilder(). - WithName("multiple-outputs"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), ). @@ -467,8 +506,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec.output", }, { + name: "legacy-http-output-using-otlp-input", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-http-output-using-otlp-input"). WithHTTPOutput(). WithOTLPInput(true). Build(), @@ -476,8 +515,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec", }, { + name: "legacy-custom-output-using-otlp-input", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-custom-output-using-otlp-input"). WithCustomOutput("name icke"). WithOTLPInput(true). Build(), @@ -485,8 +524,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec", }, { + name: "legacy-drop-labels-with-otlp-output", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-drop-labels-with-otlp-output"). WithApplicationInput(true). WithDropLabels(false). WithOTLPOutput( @@ -497,8 +536,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec", }, { + name: "legacy-keep-annotations-with-otlp-output", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-keep-annotations-with-otlp-output"). WithApplicationInput(true). WithKeepAnnotations(false). WithOTLPOutput( @@ -509,8 +548,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec", }, { + name: "legacy-files-with-otlp-output", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-files-with-otlp-output"). WithApplicationInput(false). WithFile("file1.json", "icke"). WithOTLPOutput( @@ -521,8 +560,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec", }, { + name: "legacy-filters-with-otlp-output", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-filters-with-otlp-output"). WithApplicationInput(false). WithCustomFilter("name grep"). WithOTLPOutput( @@ -533,8 +572,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec", }, { + name: "legacy-variables-with-otlp-output", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-variables-with-otlp-output"). WithApplicationInput(false). WithVariable("var1", "secName", "secNs", "secKey"). WithOTLPOutput( @@ -545,8 +584,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec", }, { + name: "legacy-transform-with-http-output", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-transform-with-http-output"). WithApplicationInput(false). WithTransform(telemetryv1alpha1.TransformSpec{ Statements: []string{"set(attributes[\"log.level\"], \"error\")", "set(body, \"transformed1\")"}, @@ -557,8 +596,8 @@ func TestRejectLogPipelineCreation(t *testing.T) { field: "spec", }, { + name: "legacy-filter-with-http-output", pipeline: testutils.NewLogPipelineBuilder(). - WithName("legacy-filter-with-http-output"). WithApplicationInput(false). WithFilter(telemetryv1alpha1.FilterSpec{ Conditions: []string{"isMatch(log.attributes[\"log.level\"], \"error\"))"}, @@ -570,12 +609,10 @@ func TestRejectLogPipelineCreation(t *testing.T) { }, } for _, tc := range tests { - if tc.label == "" { - tc.label = suite.LabelLogsMisc - } + t.Run(tc.name, func(t *testing.T) { + suite.RegisterTestCase(t, tc.label, suite.LabelLogsMisc) - t.Run(tc.label, func(t *testing.T) { - suite.RegisterTestCase(t, tc.label) + tc.pipeline.Name = tc.name resources := []client.Object{&tc.pipeline} diff --git a/test/e2e/logs/shared/check_metrics_endpoint_test.go b/test/e2e/logs/shared/check_metrics_endpoint_test.go index c2fc4abaa0..17b8b226ab 100644 --- a/test/e2e/logs/shared/check_metrics_endpoint_test.go +++ b/test/e2e/logs/shared/check_metrics_endpoint_test.go @@ -61,7 +61,7 @@ func TestMetricsEndpoint_OTel(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(tc.input). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/shared/container_selector_test.go b/test/e2e/logs/shared/container_selector_test.go index 1027afc46b..90abcc71bd 100644 --- a/test/e2e/logs/shared/container_selector_test.go +++ b/test/e2e/logs/shared/container_selector_test.go @@ -38,7 +38,7 @@ func TestContainerSelector_OTel(t *testing.T) { WithName(includePipelineName). WithIncludeContainers(container1). WithIncludeNamespaces(genNs). - WithOTLPOutput(testutils.OTLPEndpoint(backend1.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend1.EndpointHTTP())). Build() // Exclude container1 from namespace genNs @@ -46,7 +46,7 @@ func TestContainerSelector_OTel(t *testing.T) { WithName(excludePipelineName). WithExcludeContainers(container1). WithIncludeNamespaces(genNs). - WithOTLPOutput(testutils.OTLPEndpoint(backend2.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend2.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/shared/disabled_input_test.go b/test/e2e/logs/shared/disabled_input_test.go index c646e0f9f7..42c17e928d 100644 --- a/test/e2e/logs/shared/disabled_input_test.go +++ b/test/e2e/logs/shared/disabled_input_test.go @@ -38,7 +38,7 @@ func TestDisabledInput_OTel(t *testing.T) { WithApplicationInput(false). WithOTLPInput(false). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), + testutils.OTLPEndpoint(backend.EndpointHTTP()), ). Build() diff --git a/test/e2e/logs/shared/extract_labels_test.go b/test/e2e/logs/shared/extract_labels_test.go index 285b698b75..e375d717c6 100644 --- a/test/e2e/logs/shared/extract_labels_test.go +++ b/test/e2e/logs/shared/extract_labels_test.go @@ -83,7 +83,7 @@ func TestExtractLabels_OTel(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() genLabels := map[string]string{ diff --git a/test/e2e/logs/shared/filter_test.go b/test/e2e/logs/shared/filter_test.go index a1969e05c9..c5aa25d930 100644 --- a/test/e2e/logs/shared/filter_test.go +++ b/test/e2e/logs/shared/filter_test.go @@ -53,7 +53,7 @@ func TestFilter_OTel(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). WithTransform(telemetryv1alpha1.TransformSpec{ Statements: []string{"set(log.attributes[\"test\"], \"passed\")"}, }). diff --git a/test/e2e/logs/shared/keep_original_body_test.go b/test/e2e/logs/shared/keep_original_body_test.go index 1104a6f7fb..9a73d9a1f4 100644 --- a/test/e2e/logs/shared/keep_original_body_test.go +++ b/test/e2e/logs/shared/keep_original_body_test.go @@ -66,7 +66,7 @@ func TestKeepOriginalBody_OTel(t *testing.T) { WithApplicationInput(true, []testutils.ExtendedNamespaceSelectorOptions{testutils.ExtIncludeNamespaces(sourceNsKeepOriginal)}...). WithKeepOriginalBody(true). - WithOTLPOutput(testutils.OTLPEndpoint(backendKeepOriginal.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendKeepOriginal.EndpointHTTP())). Build() pipelineDropOriginal := testutils.NewLogPipelineBuilder(). @@ -74,7 +74,7 @@ func TestKeepOriginalBody_OTel(t *testing.T) { WithApplicationInput(true, []testutils.ExtendedNamespaceSelectorOptions{testutils.ExtIncludeNamespaces(sourceNsDropOriginal)}...). WithKeepOriginalBody(false). - WithOTLPOutput(testutils.OTLPEndpoint(backendDropOriginal.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendDropOriginal.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/shared/mtls_about_to_expire_cert_test.go b/test/e2e/logs/shared/mtls_about_to_expire_cert_test.go index 6cf5e951b1..5cfa2fd870 100644 --- a/test/e2e/logs/shared/mtls_about_to_expire_cert_test.go +++ b/test/e2e/logs/shared/mtls_about_to_expire_cert_test.go @@ -51,7 +51,7 @@ func TestMTLSAboutToExpireCert_OTel(t *testing.T) { } for _, tc := range tests { t.Run(tc.label, func(t *testing.T) { - suite.RegisterTestCase(t, tc.label) + suite.RegisterTestCase(t, tc.label, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix(tc.label) @@ -65,14 +65,14 @@ func TestMTLSAboutToExpireCert_OTel(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCerts.CaCertPem.String(), clientCerts.ClientCertPem.String(), clientCerts.ClientKeyPem.String(), @@ -130,7 +130,7 @@ func TestMTLSAboutToExpireCert_FluentBit(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). diff --git a/test/e2e/logs/shared/mtls_test.go b/test/e2e/logs/shared/mtls_test.go index 7da0d3e6eb..2a3c16d21a 100644 --- a/test/e2e/logs/shared/mtls_test.go +++ b/test/e2e/logs/shared/mtls_test.go @@ -48,7 +48,7 @@ func TestMTLS_OTel(t *testing.T) { } for _, tc := range tests { t.Run(tc.label, func(t *testing.T) { - suite.RegisterTestCase(t, tc.label) + suite.RegisterTestCase(t, tc.label, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix(tc.label) @@ -60,14 +60,14 @@ func TestMTLS_OTel(t *testing.T) { serverCerts, clientCerts, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCerts.CaCertPem.String(), clientCerts.ClientCertPem.String(), clientCerts.ClientKeyPem.String()), @@ -109,7 +109,7 @@ func TestMTLS_FluentBit(t *testing.T) { serverCerts, clientCerts, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsFluentBit, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). diff --git a/test/e2e/logs/shared/multi_pipeline_broken_test.go b/test/e2e/logs/shared/multi_pipeline_broken_test.go index 0d7a0337e3..7ac7ac7029 100644 --- a/test/e2e/logs/shared/multi_pipeline_broken_test.go +++ b/test/e2e/logs/shared/multi_pipeline_broken_test.go @@ -66,7 +66,7 @@ func TestMultiPipelineBroken_OTel(t *testing.T) { healthyPipeline := testutils.NewLogPipelineBuilder(). WithName(healthyPipelineName). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() brokenPipeline := testutils.NewLogPipelineBuilder(). diff --git a/test/e2e/logs/shared/multi_pipeline_fanout_test.go b/test/e2e/logs/shared/multi_pipeline_fanout_test.go index 60670b676d..eaeff65fc1 100644 --- a/test/e2e/logs/shared/multi_pipeline_fanout_test.go +++ b/test/e2e/logs/shared/multi_pipeline_fanout_test.go @@ -64,13 +64,13 @@ func TestMultiPipelineFanout_OTel(t *testing.T) { pipeline1 := testutils.NewLogPipelineBuilder(). WithName(pipeline1Name). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend1.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend1.EndpointHTTP())). Build() pipeline2 := testutils.NewLogPipelineBuilder(). WithName(pipeline2Name). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend2.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend2.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/shared/multi_pipeline_max_pipeline_test.go b/test/e2e/logs/shared/multi_pipeline_max_pipeline_test.go index efacd80e66..328f68dda5 100644 --- a/test/e2e/logs/shared/multi_pipeline_max_pipeline_test.go +++ b/test/e2e/logs/shared/multi_pipeline_max_pipeline_test.go @@ -57,7 +57,7 @@ func TestMultiPipelineMaxPipeline(t *testing.T) { pipeline = testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(testutils.BuildLogPipelineApplicationInput()). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() } @@ -73,7 +73,7 @@ func TestMultiPipelineMaxPipeline(t *testing.T) { additionalOTelPipeline := testutils.NewLogPipelineBuilder(). WithName(additionalOTelPipelineName). WithInput(testutils.BuildLogPipelineApplicationInput()). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ @@ -161,7 +161,7 @@ func TestMultiPipelineMaxPipeline_OTel(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(testutils.BuildLogPipelineOTLPInput(testutils.IncludeNamespaces(genNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() pipelines = append(pipelines, &pipeline) } @@ -169,7 +169,7 @@ func TestMultiPipelineMaxPipeline_OTel(t *testing.T) { additionalPipeline := testutils.NewLogPipelineBuilder(). WithName(additionalPipelineName). WithInput(testutils.BuildLogPipelineOTLPInput(testutils.IncludeNamespaces(genNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/shared/namespace_selector_test.go b/test/e2e/logs/shared/namespace_selector_test.go index 3529167e9b..e404ae3d46 100644 --- a/test/e2e/logs/shared/namespace_selector_test.go +++ b/test/e2e/logs/shared/namespace_selector_test.go @@ -86,7 +86,7 @@ func TestNamespaceSelector_OTel(t *testing.T) { includePipeline := testutils.NewLogPipelineBuilder(). WithName(includePipelineName). WithInput(tc.inputBuilder([]string{gen1Ns}, nil)). - WithOTLPOutput(testutils.OTLPEndpoint(backend1.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend1.EndpointHTTP())). Build() // Exclude all namespaces except gen1Ns (gen2Ns and other unrelated namespaces) @@ -107,7 +107,7 @@ func TestNamespaceSelector_OTel(t *testing.T) { excludePipeline := testutils.NewLogPipelineBuilder(). WithName(excludePipelineName). WithInput(tc.inputBuilder(nil, excludeNss)). - WithOTLPOutput(testutils.OTLPEndpoint(backend2.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend2.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/shared/oauth2_test.go b/test/e2e/logs/shared/oauth2_test.go new file mode 100644 index 0000000000..24f75f7d43 --- /dev/null +++ b/test/e2e/logs/shared/oauth2_test.go @@ -0,0 +1,111 @@ +package shared + +import ( + "testing" + + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/client" + + telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + testutils "github.com/kyma-project/telemetry-manager/internal/utils/test" + "github.com/kyma-project/telemetry-manager/test/testkit/assert" + kitk8s "github.com/kyma-project/telemetry-manager/test/testkit/k8s" + kitk8sobjects "github.com/kyma-project/telemetry-manager/test/testkit/k8s/objects" + kitkyma "github.com/kyma-project/telemetry-manager/test/testkit/kyma" + kitbackend "github.com/kyma-project/telemetry-manager/test/testkit/mocks/backend" + "github.com/kyma-project/telemetry-manager/test/testkit/mocks/oauth2mock" + "github.com/kyma-project/telemetry-manager/test/testkit/mocks/stdoutloggen" + "github.com/kyma-project/telemetry-manager/test/testkit/mocks/telemetrygen" + "github.com/kyma-project/telemetry-manager/test/testkit/suite" + "github.com/kyma-project/telemetry-manager/test/testkit/unique" +) + +func TestOAuth2(t *testing.T) { + tests := []struct { + label string + inputBuilder func(includeNs string) telemetryv1alpha1.LogPipelineInput + logGeneratorBuilder func(ns string) client.Object + expectAgent bool + }{ + { + label: suite.LabelLogAgent, + inputBuilder: func(includeNs string) telemetryv1alpha1.LogPipelineInput { + return testutils.BuildLogPipelineApplicationInput(testutils.ExtIncludeNamespaces(includeNs)) + }, + logGeneratorBuilder: func(ns string) client.Object { + return stdoutloggen.NewDeployment(ns).K8sObject() + }, + expectAgent: true, + }, + { + label: suite.LabelLogGateway, + inputBuilder: func(includeNs string) telemetryv1alpha1.LogPipelineInput { + return testutils.BuildLogPipelineOTLPInput(testutils.IncludeNamespaces(includeNs)) + }, + logGeneratorBuilder: func(ns string) client.Object { + return telemetrygen.NewDeployment(ns, telemetrygen.SignalTypeLogs).K8sObject() + }, + }, + } + + for _, tc := range tests { + t.Run(tc.label, func(t *testing.T) { + suite.RegisterTestCase(t, tc.label, suite.LabelOAuth2) + + var ( + uniquePrefix = unique.Prefix(tc.label) + pipelineName = uniquePrefix() + backendNs = uniquePrefix("backend") + genNs = uniquePrefix("gen") + ) + + oauth2server := oauth2mock.New(backendNs) + + serverCerts, _, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() + Expect(err).ToNot(HaveOccurred()) + + backend := kitbackend.New(backendNs, kitbackend.SignalTypeLogsOTel, + kitbackend.WithTLS(*serverCerts), + kitbackend.WithOIDCAuth(oauth2server.IssuerURL(), oauth2server.Audience()), + ) + + pipeline := testutils.NewLogPipelineBuilder(). + WithName(pipelineName). + WithInput(tc.inputBuilder(genNs)). + WithOTLPOutput( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPOAuth2( + testutils.OAuth2ClientID("the-mock-does-not-verify"), + testutils.OAuth2ClientSecret("the-mock-does-not-verify"), + testutils.OAuth2TokenURL(oauth2server.TokenEndpoint()), + testutils.OAuth2Params(map[string]string{"grant_type": "client_credentials"}), + ), + testutils.OTLPClientTLSFromString(serverCerts.CaCertPem.String()), + ). + Build() + + resources := []client.Object{ + kitk8sobjects.NewNamespace(backendNs).K8sObject(), + kitk8sobjects.NewNamespace(genNs).K8sObject(), + &pipeline, + tc.logGeneratorBuilder(genNs), + } + + resources = append(resources, oauth2server.K8sObjects()...) + resources = append(resources, backend.K8sObjects()...) + + Expect(kitk8s.CreateObjects(t, resources...)).To(Succeed()) + + assert.DeploymentReady(t, oauth2server.NamespacedName()) + assert.BackendReachable(t, backend) + assert.DeploymentReady(t, kitkyma.LogGatewayName) + + if tc.expectAgent { + assert.DaemonSetReady(t, kitkyma.LogAgentName) + } + + assert.OTelLogPipelineHealthy(t, pipelineName) + assert.OTelLogsFromNamespaceDelivered(t, backend, genNs) + }) + } +} diff --git a/test/e2e/logs/shared/observed_time_test.go b/test/e2e/logs/shared/observed_time_test.go index a95791af84..2d305aea70 100644 --- a/test/e2e/logs/shared/observed_time_test.go +++ b/test/e2e/logs/shared/observed_time_test.go @@ -63,7 +63,7 @@ func TestObservedTime_OTel(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/shared/secret_rotation_test.go b/test/e2e/logs/shared/secret_rotation_test.go index 334c51260c..25e789c8bf 100644 --- a/test/e2e/logs/shared/secret_rotation_test.go +++ b/test/e2e/logs/shared/secret_rotation_test.go @@ -101,7 +101,7 @@ func TestSecretRotation_OTel(t *testing.T) { assert.OTelLogsFromNamespaceNotDelivered(t, backend, genNs) // Update the secret to have the correct backend endpoint - secret.UpdateSecret(kitk8sobjects.WithStringData(endpointKey, backend.Endpoint())) + secret.UpdateSecret(kitk8sobjects.WithStringData(endpointKey, backend.EndpointHTTP())) Expect(kitk8s.UpdateObjects(t, secret.K8sObject())).To(Succeed()) assert.DeploymentReady(t, kitkyma.LogGatewayName) diff --git a/test/e2e/logs/shared/single_pipeline_test.go b/test/e2e/logs/shared/single_pipeline_test.go index 11fd05ef3e..a8c115734a 100644 --- a/test/e2e/logs/shared/single_pipeline_test.go +++ b/test/e2e/logs/shared/single_pipeline_test.go @@ -63,7 +63,7 @@ func TestSinglePipeline_OTel(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/logs/shared/transform_test.go b/test/e2e/logs/shared/transform_test.go index c715fefe97..d5e4e6ad8a 100644 --- a/test/e2e/logs/shared/transform_test.go +++ b/test/e2e/logs/shared/transform_test.go @@ -149,7 +149,7 @@ func TestTransform_OTel(t *testing.T) { pipelineTransform := testutils.NewLogPipelineBuilder(). WithName(pipelineNameValue). WithInput(tc.input). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). WithTransform(tc.transformSpec). Build() diff --git a/test/e2e/metrics/agent/prometheus_input_diagnostic_metric_test.go b/test/e2e/metrics/agent/prometheus_input_diagnostic_metric_test.go index fa524cd1e0..06ba37c772 100644 --- a/test/e2e/metrics/agent/prometheus_input_diagnostic_metric_test.go +++ b/test/e2e/metrics/agent/prometheus_input_diagnostic_metric_test.go @@ -43,7 +43,7 @@ func TestPrometheusInputDiagnosticMetric(t *testing.T) { WithName(pipelineName). WithPrometheusInput(true). WithPrometheusInputDiagnosticMetrics(true). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/agent/prometheus_input_test.go b/test/e2e/metrics/agent/prometheus_input_test.go index e76f5f414b..fe827fb61e 100644 --- a/test/e2e/metrics/agent/prometheus_input_test.go +++ b/test/e2e/metrics/agent/prometheus_input_test.go @@ -39,7 +39,7 @@ func TestPrometheusInput(t *testing.T) { pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithPrometheusInput(true, testutils.IncludeNamespaces(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/agent/runtime_input_test.go b/test/e2e/metrics/agent/runtime_input_test.go index 748c7fa5db..7e5ddc6cb0 100644 --- a/test/e2e/metrics/agent/runtime_input_test.go +++ b/test/e2e/metrics/agent/runtime_input_test.go @@ -29,7 +29,7 @@ import ( ) func TestRuntimeInput(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelGardener, suite.LabelMetricAgentSetC) + suite.RegisterTestCase(t, suite.LabelGardener, suite.LabelMetricAgentSetB) const ( podNetworkErrorsMetric = "k8s.pod.network.errors" @@ -77,7 +77,7 @@ func TestRuntimeInput(t *testing.T) { WithRuntimeInputStatefulSetMetrics(false). WithRuntimeInputDaemonSetMetrics(false). WithRuntimeInputJobMetrics(false). - WithOTLPOutput(testutils.OTLPEndpoint(backendA.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendA.EndpointHTTP())). Build() pipelineB := testutils.NewMetricPipelineBuilder(). WithName(pipelineNameB). @@ -90,12 +90,12 @@ func TestRuntimeInput(t *testing.T) { WithRuntimeInputStatefulSetMetrics(true). WithRuntimeInputDaemonSetMetrics(true). WithRuntimeInputJobMetrics(true). - WithOTLPOutput(testutils.OTLPEndpoint(backendB.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendB.EndpointHTTP())). Build() pipelineC := testutils.NewMetricPipelineBuilder(). WithName(pipelineNameC). WithRuntimeInput(true, testutils.IncludeNamespaces(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backendC.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendC.EndpointHTTP())). Build() prometheusMetricGen := prommetricgen.New(genNs) diff --git a/test/e2e/metrics/agent/runtime_node_namespace_test.go b/test/e2e/metrics/agent/runtime_node_namespace_test.go index dbc5bc6e52..833e015f11 100644 --- a/test/e2e/metrics/agent/runtime_node_namespace_test.go +++ b/test/e2e/metrics/agent/runtime_node_namespace_test.go @@ -20,7 +20,7 @@ import ( ) func TestRuntimeNodeNamespace(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelMetricAgentSetC) + suite.RegisterTestCase(t, suite.LabelMetricAgentSetB) var ( uniquePrefix = unique.Prefix() @@ -43,7 +43,7 @@ func TestRuntimeNodeNamespace(t *testing.T) { WithRuntimeInputPodMetrics(false). WithRuntimeInputContainerMetrics(false). WithRuntimeInputVolumeMetrics(false). - WithOTLPOutput(testutils.OTLPEndpoint(includeBacked.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(includeBacked.EndpointHTTP())). Build() excludePipeline := testutils.NewMetricPipelineBuilder(). WithName(excludePipelineName). @@ -52,7 +52,7 @@ func TestRuntimeNodeNamespace(t *testing.T) { WithRuntimeInputPodMetrics(false). WithRuntimeInputContainerMetrics(false). WithRuntimeInputVolumeMetrics(false). - WithOTLPOutput(testutils.OTLPEndpoint(excludeBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(excludeBackend.EndpointHTTP())). Build() includeMetricProducer := prommetricgen.New(includeNs) diff --git a/test/e2e/metrics/agent/service_name_test.go b/test/e2e/metrics/agent/service_name_test.go index 61f25fd7e5..fb5ca28529 100644 --- a/test/e2e/metrics/agent/service_name_test.go +++ b/test/e2e/metrics/agent/service_name_test.go @@ -19,7 +19,7 @@ import ( ) func TestServiceName(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelMetricAgentSetC) + suite.RegisterTestCase(t, suite.LabelMetricAgentSetB) const ( jobName = "job" @@ -44,7 +44,7 @@ func TestServiceName(t *testing.T) { pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithRuntimeInput(true, testutils.IncludeNamespaces(kitkyma.SystemNamespaceName)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() podSpecWithUndefinedService := telemetrygen.PodSpec(telemetrygen.SignalTypeMetrics, diff --git a/test/e2e/metrics/gateway/enrichment_values_empty_test.go b/test/e2e/metrics/gateway/enrichment_values_empty_test.go index 2d2e2d8036..175a6f2ff8 100644 --- a/test/e2e/metrics/gateway/enrichment_values_empty_test.go +++ b/test/e2e/metrics/gateway/enrichment_values_empty_test.go @@ -31,7 +31,7 @@ func TestEnrichmentValuesEmpty(t *testing.T) { backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() // All attributes in the enrichment flow are set to empty values diff --git a/test/e2e/metrics/gateway/enrichment_values_predefined_test.go b/test/e2e/metrics/gateway/enrichment_values_predefined_test.go index a371df0d4b..034a3280c3 100644 --- a/test/e2e/metrics/gateway/enrichment_values_predefined_test.go +++ b/test/e2e/metrics/gateway/enrichment_values_predefined_test.go @@ -31,7 +31,7 @@ func TestEnrichmentValuesPredefined(t *testing.T) { backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() // All attributes in the enrichment flow are set to predefined values diff --git a/test/e2e/metrics/gateway/kyma_input_test.go b/test/e2e/metrics/gateway/kyma_input_test.go index 7614cc9b06..9df0986a4a 100644 --- a/test/e2e/metrics/gateway/kyma_input_test.go +++ b/test/e2e/metrics/gateway/kyma_input_test.go @@ -40,14 +40,14 @@ func TestKymaInput(t *testing.T) { pipelineWithKymaOnly := testutils.NewMetricPipelineBuilder(). WithName(pipelineNameKymaOnly). WithOTLPInput(false). - WithOTLPOutput(testutils.OTLPEndpoint(backendKymaOnly.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendKymaOnly.EndpointHTTP())). Build() // one pipeline with Kyma input and additional namespace included. Here we expect metrics from generatorNs pipelineWithKymaAndOtlp := testutils.NewMetricPipelineBuilder(). WithName(pipelineNameKymaAndOtlp). WithOTLPInput(true, testutils.IncludeNamespaces(generatorNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backendKymaAndOtlp.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendKymaAndOtlp.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/misc/disabled_input_test.go b/test/e2e/metrics/misc/disabled_input_test.go index 9aa9999b07..ae79f17b77 100644 --- a/test/e2e/metrics/misc/disabled_input_test.go +++ b/test/e2e/metrics/misc/disabled_input_test.go @@ -37,7 +37,7 @@ func TestDisabledInput(t *testing.T) { WithRuntimeInput(false). WithIstioInput(false). WithOTLPInput(false). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/misc/mtls_cert_key_pair_dont_match_test.go b/test/e2e/metrics/misc/mtls_cert_key_pair_dont_match_test.go index 5ed5e61f0f..34de5b97e2 100644 --- a/test/e2e/metrics/misc/mtls_cert_key_pair_dont_match_test.go +++ b/test/e2e/metrics/misc/mtls_cert_key_pair_dont_match_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSCertKeyPairDontMatch(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelMetricsMisc) + suite.RegisterTestCase(t, suite.LabelMetricsMisc, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -32,13 +32,13 @@ func TestMTLSCertKeyPairDontMatch(t *testing.T) { _, clientCertsCreatedAgain, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithTLS(*serverCertsDefault)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithMTLS(*serverCertsDefault)) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCertsDefault.CaCertPem.String(), clientCertsDefault.ClientCertPem.String(), clientCertsCreatedAgain.ClientKeyPem.String(), // Use different key diff --git a/test/e2e/metrics/misc/mtls_expired_cert_test.go b/test/e2e/metrics/misc/mtls_expired_cert_test.go index ffda1ddff2..33ee3f29d0 100644 --- a/test/e2e/metrics/misc/mtls_expired_cert_test.go +++ b/test/e2e/metrics/misc/mtls_expired_cert_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSExpiredCert(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelMetricsMisc) + suite.RegisterTestCase(t, suite.LabelMetricsMisc, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSExpiredCert(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithTLS(*expiredServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithMTLS(*expiredServerCerts)) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( expiredClientCerts.CaCertPem.String(), expiredClientCerts.ClientCertPem.String(), expiredClientCerts.ClientKeyPem.String(), diff --git a/test/e2e/metrics/misc/mtls_invalid_ca_test.go b/test/e2e/metrics/misc/mtls_invalid_ca_test.go index 2ba931b945..77663b3a81 100644 --- a/test/e2e/metrics/misc/mtls_invalid_ca_test.go +++ b/test/e2e/metrics/misc/mtls_invalid_ca_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSInvalidCA(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelMetricsMisc) + suite.RegisterTestCase(t, suite.LabelMetricsMisc, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSInvalidCA(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithTLS(*invalidServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithMTLS(*invalidServerCerts)) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( invalidClientCerts.CaCertPem.String(), invalidClientCerts.ClientCertPem.String(), invalidClientCerts.ClientKeyPem.String(), diff --git a/test/e2e/metrics/misc/mtls_invalid_cert_test.go b/test/e2e/metrics/misc/mtls_invalid_cert_test.go index 89905abb55..0de62863ce 100644 --- a/test/e2e/metrics/misc/mtls_invalid_cert_test.go +++ b/test/e2e/metrics/misc/mtls_invalid_cert_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSInvalidCert(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelMetricsMisc) + suite.RegisterTestCase(t, suite.LabelMetricsMisc, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSInvalidCert(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithTLS(*invalidServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithMTLS(*invalidServerCerts)) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( invalidClientCerts.CaCertPem.String(), invalidClientCerts.ClientCertPem.String(), invalidClientCerts.ClientKeyPem.String(), diff --git a/test/e2e/metrics/misc/mtls_missing_key_test.go b/test/e2e/metrics/misc/mtls_missing_key_test.go index 43b5203e75..1dcff70482 100644 --- a/test/e2e/metrics/misc/mtls_missing_key_test.go +++ b/test/e2e/metrics/misc/mtls_missing_key_test.go @@ -31,12 +31,12 @@ func TestMTLSMissingKey(t *testing.T) { serverCerts, clientCerts, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), + testutils.OTLPEndpoint(backend.EndpointHTTP()), testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ CA: &telemetryv1alpha1.ValueType{Value: clientCerts.CaCertPem.String()}, Cert: &telemetryv1alpha1.ValueType{Value: clientCerts.ClientCertPem.String()}, diff --git a/test/e2e/metrics/misc/reject_creation_test.go b/test/e2e/metrics/misc/reject_creation_test.go index c56e35e670..7960b57f01 100644 --- a/test/e2e/metrics/misc/reject_creation_test.go +++ b/test/e2e/metrics/misc/reject_creation_test.go @@ -7,7 +7,6 @@ import ( . "github.com/onsi/gomega" apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" @@ -27,6 +26,7 @@ func TestRejectPipelineCreation(t *testing.T) { var backenEndpoint = backendHost + ":" + strconv.Itoa(backendPort) tests := []struct { + name string pipeline telemetryv1alpha1.MetricPipeline errorMsg string field string @@ -34,10 +34,8 @@ func TestRejectPipelineCreation(t *testing.T) { }{ // output general { + name: "no-output", pipeline: telemetryv1alpha1.MetricPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "no-output", - }, Spec: telemetryv1alpha1.MetricPipelineSpec{}, }, errorMsg: "must be of type object", @@ -45,10 +43,8 @@ func TestRejectPipelineCreation(t *testing.T) { causes: 2, }, { + name: "valuefrom-accepts-only-one-option", pipeline: telemetryv1alpha1.MetricPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "valuefrom-accepts-only-one-option", - }, Spec: telemetryv1alpha1.MetricPipelineSpec{ Output: telemetryv1alpha1.MetricPipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -70,10 +66,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint", }, { + name: "secretkeyref-requires-key", pipeline: telemetryv1alpha1.MetricPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-key", - }, Spec: telemetryv1alpha1.MetricPipelineSpec{ Output: telemetryv1alpha1.MetricPipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -93,10 +87,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint.valueFrom.secretKeyRef.key", }, { + name: "secretkeyref-requires-namespace", pipeline: telemetryv1alpha1.MetricPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-namespace", - }, Spec: telemetryv1alpha1.MetricPipelineSpec{ Output: telemetryv1alpha1.MetricPipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -116,10 +108,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint.valueFrom.secretKeyRef.namespace", }, { + name: "secretkeyref-requires-name", pipeline: telemetryv1alpha1.MetricPipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-name", - }, Spec: telemetryv1alpha1.MetricPipelineSpec{ Output: telemetryv1alpha1.MetricPipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -140,8 +130,8 @@ func TestRejectPipelineCreation(t *testing.T) { }, // otlp output { + name: "otlp-output-with-default-proto-and-path", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-output-with-default-proto-and-path"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPEndpointPath("/v1/dummy"), @@ -151,8 +141,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp", }, { + name: "otlp-output-with-grpc-proto-and-path", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-output-with-grpc-proto-and-path"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPEndpointPath("/v1/dummy"), @@ -163,8 +153,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp", }, { + name: "otlp-output-with-non-valid-proto", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-output-with-non-valid-proto"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPProtocol("icke"), @@ -175,8 +165,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp.protocol", }, { + name: "otlp-output-basic-auth-secretref-missing-password-key", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-output-basic-auth-secretref-missing-password-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPBasicAuthFromSecret("name", "namespace", "user", ""), @@ -186,8 +176,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.key", }, { + name: "otlp-output-basic-auth-secretref-missing-user-key", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-output-basic-auth-secretref-missing-user-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPBasicAuthFromSecret("name", "namespace", "", "password"), @@ -197,8 +187,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.key", }, { + name: "otlp-output-tls-missing-key", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-output-tls-missing-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ @@ -211,8 +201,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.output.otlp.tls", }, { + name: "otlp-output-tls-missing-cert", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-output-tls-missing-cert"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ @@ -224,10 +214,57 @@ func TestRejectPipelineCreation(t *testing.T) { errorMsg: "Can define either both 'cert' and 'key', or neither", field: "spec.output.otlp.tls", }, + { + name: "otlp-output-oauth2-invalid-token-url", + pipeline: testutils.NewMetricPipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2ClientID("clientid"), + testutils.OAuth2TokenURL("../not-a-url"), + ), + ). + Build(), + errorMsg: "Invalid value: \"object\": 'tokenURL' must be a valid URL", + field: "spec.output.otlp.authentication.oauth2.tokenURL", + }, + { + name: "otlp-output-oauth2-missing-client-id", + pipeline: testutils.NewMetricPipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2TokenURL("https://auth.example.com/token"), + ), + ). + Build(), + errorMsg: "Invalid value: \"object\": no such key: value evaluating rule: 'clientID' missing", + field: "spec.output.otlp.authentication.oauth2.clientID", + }, + { + name: "otlp-output-oauth2-insecure", + pipeline: testutils.NewMetricPipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientID("clientid"), + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2TokenURL("https://auth.example.com/token"), + ), + testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ + Insecure: true, + }), + ). + Build(), + errorMsg: "OAuth2 authentication requires TLS when using gRPC protocol", + field: "spec.output.otlp", + }, // otlp input { + name: "otlp-input-namespaces-not-exclusive", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-input-namespaces-not-exclusive"). WithOTLPInput(true, testutils.ExcludeNamespaces("ns1"), testutils.IncludeNamespaces("ns2"), @@ -238,8 +275,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.input.otlp.namespaces", }, { + name: "otlp-input-namespaces-include-invalid", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-input-namespaces-include-invalid"). WithOTLPInput(true, testutils.IncludeNamespaces("aa!"), ). @@ -249,8 +286,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.input.otlp.namespaces.include[0]", }, { + name: "otlp-input-namespaces-exclude-invalid", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("otlp-input-namespaces-exclude-invalid"). WithOTLPInput(true, testutils.ExcludeNamespaces("aa!"), ). @@ -261,8 +298,8 @@ func TestRejectPipelineCreation(t *testing.T) { }, // prometheus input { + name: "prometheus-input-namespaces-include-invalid", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("prometheus-input-namespaces-include-invalid"). WithPrometheusInput(true, testutils.IncludeNamespaces("aa-"), ). @@ -272,8 +309,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.input.prometheus.namespaces.include[0]", }, { + name: "prometheus-input-namespaces-exclude-invalid", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("prometheus-input-namespaces-exclude-invalid"). WithPrometheusInput(true, testutils.ExcludeNamespaces("-aa"), ). @@ -284,8 +321,8 @@ func TestRejectPipelineCreation(t *testing.T) { }, // istio input { + name: "istio-input-namespaces-include-invalid", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("istio-input-namespaces-include-invalid"). WithIstioInput(true, testutils.IncludeNamespaces("#"), ). @@ -295,8 +332,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.input.istio.namespaces.include[0]", }, { + name: "istio-input-namespaces-exclude-invalid", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("istio-input-namespaces-exclude-invalid"). WithIstioInput(true, testutils.ExcludeNamespaces("/"), ). @@ -307,8 +344,8 @@ func TestRejectPipelineCreation(t *testing.T) { }, // runtime input { + name: "istio-input-namespaces-include-invalid", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("istio-input-namespaces-include-invalid"). WithRuntimeInput(true, testutils.IncludeNamespaces("aa", "bb", "??"), ). @@ -318,8 +355,8 @@ func TestRejectPipelineCreation(t *testing.T) { field: "spec.input.runtime.namespaces.include[2]", }, { + name: "istio-input-namespaces-exclude-invalid", pipeline: testutils.NewMetricPipelineBuilder(). - WithName("istio-input-namespaces-exclude-invalid"). WithRuntimeInput(true, testutils.ExcludeNamespaces("öö", "aa", "bb"), ). @@ -330,9 +367,11 @@ func TestRejectPipelineCreation(t *testing.T) { }, } for _, tc := range tests { - t.Run(suite.LabelMisc, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { suite.RegisterTestCase(t, suite.LabelMisc) + tc.pipeline.Name = tc.name + resources := []client.Object{&tc.pipeline} err := kitk8s.CreateObjects(t, resources...) diff --git a/test/e2e/metrics/shared/cloud_provider_attributes_test.go b/test/e2e/metrics/shared/cloud_provider_attributes_test.go index 693289fe4a..7450a42b35 100644 --- a/test/e2e/metrics/shared/cloud_provider_attributes_test.go +++ b/test/e2e/metrics/shared/cloud_provider_attributes_test.go @@ -77,7 +77,7 @@ func TestCloudProviderAttributes(t *testing.T) { WithRuntimeInputStatefulSetMetrics(false). WithRuntimeInputDaemonSetMetrics(false). WithRuntimeInputJobMetrics(false). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/shared/custom_cluster_name_test.go b/test/e2e/metrics/shared/custom_cluster_name_test.go index 88c69bf272..6105387f9b 100644 --- a/test/e2e/metrics/shared/custom_cluster_name_test.go +++ b/test/e2e/metrics/shared/custom_cluster_name_test.go @@ -73,7 +73,7 @@ func TestCustomClusterName(t *testing.T) { pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithInput(tc.input). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() kitk8s.PreserveAndScheduleRestoreOfTelemetryResource(t, kitkyma.TelemetryName) diff --git a/test/e2e/metrics/shared/extract_labels_test.go b/test/e2e/metrics/shared/extract_labels_test.go index ca06daea70..6e79ca81af 100644 --- a/test/e2e/metrics/shared/extract_labels_test.go +++ b/test/e2e/metrics/shared/extract_labels_test.go @@ -83,7 +83,7 @@ func TestExtractLabels(t *testing.T) { pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithInput(tc.input). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() genLabels := map[string]string{ diff --git a/test/e2e/metrics/shared/filter_test.go b/test/e2e/metrics/shared/filter_test.go index d0c76a2ef4..9eba8804a5 100644 --- a/test/e2e/metrics/shared/filter_test.go +++ b/test/e2e/metrics/shared/filter_test.go @@ -52,7 +52,7 @@ func TestFilter(t *testing.T) { pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). WithTransform(telemetryv1alpha1.TransformSpec{ Statements: []string{"set(datapoint.attributes[\"test\"], \"passed\")"}, }). diff --git a/test/e2e/metrics/shared/mtls_about_to_expire_cert_test.go b/test/e2e/metrics/shared/mtls_about_to_expire_cert_test.go index 41496d581d..96e5d654b0 100644 --- a/test/e2e/metrics/shared/mtls_about_to_expire_cert_test.go +++ b/test/e2e/metrics/shared/mtls_about_to_expire_cert_test.go @@ -59,7 +59,7 @@ func TestMTLSAboutToExpireCert(t *testing.T) { for _, tc := range tests { t.Run(tc.label, func(t *testing.T) { - suite.RegisterTestCase(t, tc.label) + suite.RegisterTestCase(t, tc.label, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix(tc.label) @@ -73,14 +73,14 @@ func TestMTLSAboutToExpireCert(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCerts.CaCertPem.String(), clientCerts.ClientCertPem.String(), clientCerts.ClientKeyPem.String(), diff --git a/test/e2e/metrics/shared/mtls_test.go b/test/e2e/metrics/shared/mtls_test.go index 9a301f0ad6..6359f32dad 100644 --- a/test/e2e/metrics/shared/mtls_test.go +++ b/test/e2e/metrics/shared/mtls_test.go @@ -28,7 +28,7 @@ func TestMTLS(t *testing.T) { generatorBuilder func(ns string) []client.Object }{ { - label: suite.LabelMetricAgentSetB, + label: suite.LabelMetricAgentSetC, inputBuilder: func(includeNs string) telemetryv1alpha1.MetricPipelineInput { return testutils.BuildMetricPipelineRuntimeInput(testutils.IncludeNamespaces(includeNs)) }, @@ -56,7 +56,7 @@ func TestMTLS(t *testing.T) { for _, tc := range tests { t.Run(tc.label, func(t *testing.T) { - suite.RegisterTestCase(t, tc.label) + suite.RegisterTestCase(t, suite.LabelMTLS, tc.label) var ( uniquePrefix = unique.Prefix(tc.label) @@ -68,14 +68,14 @@ func TestMTLS(t *testing.T) { serverCerts, clientCerts, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCerts.CaCertPem.String(), clientCerts.ClientCertPem.String(), clientCerts.ClientKeyPem.String(), diff --git a/test/e2e/metrics/shared/multi_pipeline_broken_test.go b/test/e2e/metrics/shared/multi_pipeline_broken_test.go index 9d5129ec16..25a1f9d670 100644 --- a/test/e2e/metrics/shared/multi_pipeline_broken_test.go +++ b/test/e2e/metrics/shared/multi_pipeline_broken_test.go @@ -30,7 +30,7 @@ func TestMultiPipelineBroken(t *testing.T) { generatorBuilder func(ns string) []client.Object }{ { - label: suite.LabelMetricAgentSetB, + label: suite.LabelMetricAgentSetC, inputBuilder: func(includeNs string) telemetryv1alpha1.MetricPipelineInput { return testutils.BuildMetricPipelineRuntimeInput(testutils.IncludeNamespaces(includeNs)) }, @@ -73,7 +73,7 @@ func TestMultiPipelineBroken(t *testing.T) { healthyPipeline := testutils.NewMetricPipelineBuilder(). WithName(healthyPipelineName). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() brokenPipeline := testutils.NewMetricPipelineBuilder(). diff --git a/test/e2e/metrics/shared/multi_pipeline_fanout_test.go b/test/e2e/metrics/shared/multi_pipeline_fanout_test.go index 73b06d76f0..9a19936c8f 100644 --- a/test/e2e/metrics/shared/multi_pipeline_fanout_test.go +++ b/test/e2e/metrics/shared/multi_pipeline_fanout_test.go @@ -25,7 +25,7 @@ import ( ) func TestMultiPipelineFanout_Agent(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelMetricAgentSetB) + suite.RegisterTestCase(t, suite.LabelMetricAgentSetC) var ( uniquePrefix = unique.Prefix() @@ -53,13 +53,13 @@ func TestMultiPipelineFanout_Agent(t *testing.T) { WithRuntimeInputStatefulSetMetrics(false). WithRuntimeInputDaemonSetMetrics(false). WithRuntimeInputJobMetrics(false). - WithOTLPOutput(testutils.OTLPEndpoint(backendRuntime.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendRuntime.EndpointHTTP())). Build() metricPipelinePrometheus := testutils.NewMetricPipelineBuilder(). WithName(pipelinePrometheusName). WithPrometheusInput(true, testutils.IncludeNamespaces(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backendPrometheus.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backendPrometheus.EndpointHTTP())). Build() metricProducer := prommetricgen.New(genNs) @@ -173,12 +173,12 @@ func TestMultiPipelineFanout_Gateway(t *testing.T) { pipeline1 := testutils.NewMetricPipelineBuilder(). WithName(pipeline1Name). - WithOTLPOutput(testutils.OTLPEndpoint(backend1.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend1.EndpointHTTP())). Build() pipeline2 := testutils.NewMetricPipelineBuilder(). WithName(pipeline2Name). - WithOTLPOutput(testutils.OTLPEndpoint(backend2.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend2.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/shared/multi_pipeline_max_pipeline_test.go b/test/e2e/metrics/shared/multi_pipeline_max_pipeline_test.go index 76e7f0a1de..84ac05b104 100644 --- a/test/e2e/metrics/shared/multi_pipeline_max_pipeline_test.go +++ b/test/e2e/metrics/shared/multi_pipeline_max_pipeline_test.go @@ -43,7 +43,7 @@ func TestMultiPipelineMaxPipeline(t *testing.T) { pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithRuntimeInput(true). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() pipelines = append(pipelines, &pipeline) } @@ -51,7 +51,7 @@ func TestMultiPipelineMaxPipeline(t *testing.T) { additionalPipeline := testutils.NewMetricPipelineBuilder(). WithName(additionalPipelineName). WithRuntimeInput(true). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/shared/namespace_selector_test.go b/test/e2e/metrics/shared/namespace_selector_test.go index eddcbd7e91..1a25582e8f 100644 --- a/test/e2e/metrics/shared/namespace_selector_test.go +++ b/test/e2e/metrics/shared/namespace_selector_test.go @@ -28,7 +28,7 @@ func TestNamespaceSelector(t *testing.T) { generatorBuilder func(ns1, ns2 string) []client.Object }{ { - label: suite.LabelMetricAgentSetB, + label: suite.LabelMetricAgentSetC, inputBuilder: func(includeNss, excludeNss []string) telemetryv1alpha1.MetricPipelineInput { var opts []testutils.NamespaceSelectorOptions if len(includeNss) > 0 { @@ -95,7 +95,7 @@ func TestNamespaceSelector(t *testing.T) { includePipeline := testutils.NewMetricPipelineBuilder(). WithName(includePipelineName). WithInput(tc.inputBuilder([]string{gen1Ns}, nil)). - WithOTLPOutput(testutils.OTLPEndpoint(backend1.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend1.EndpointHTTP())). Build() // Exclude all namespaces except gen2Ns (gen1Ns and other unrelated namespaces) @@ -116,7 +116,7 @@ func TestNamespaceSelector(t *testing.T) { excludePipeline := testutils.NewMetricPipelineBuilder(). WithName(excludePipelineName). WithInput(tc.inputBuilder(nil, excludeNss)). - WithOTLPOutput(testutils.OTLPEndpoint(backend2.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend2.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/shared/oauth2_test.go b/test/e2e/metrics/shared/oauth2_test.go new file mode 100644 index 0000000000..ccb269a442 --- /dev/null +++ b/test/e2e/metrics/shared/oauth2_test.go @@ -0,0 +1,128 @@ +package shared + +import ( + "testing" + + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/client" + + telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" + "github.com/kyma-project/telemetry-manager/internal/otelcollector/ports" + testutils "github.com/kyma-project/telemetry-manager/internal/utils/test" + "github.com/kyma-project/telemetry-manager/test/testkit/assert" + kitk8s "github.com/kyma-project/telemetry-manager/test/testkit/k8s" + kitk8sobjects "github.com/kyma-project/telemetry-manager/test/testkit/k8s/objects" + kitkyma "github.com/kyma-project/telemetry-manager/test/testkit/kyma" + "github.com/kyma-project/telemetry-manager/test/testkit/metrics/runtime" + kitbackend "github.com/kyma-project/telemetry-manager/test/testkit/mocks/backend" + "github.com/kyma-project/telemetry-manager/test/testkit/mocks/oauth2mock" + "github.com/kyma-project/telemetry-manager/test/testkit/mocks/prommetricgen" + "github.com/kyma-project/telemetry-manager/test/testkit/mocks/telemetrygen" + "github.com/kyma-project/telemetry-manager/test/testkit/suite" + "github.com/kyma-project/telemetry-manager/test/testkit/unique" +) + +func TestOAuth2(t *testing.T) { + tests := []struct { + label string + inputBuilder func(includeNs string) telemetryv1alpha1.MetricPipelineInput + generatorBuilder func(ns string) []client.Object + }{ + { + label: suite.LabelMetricAgentSetC, + inputBuilder: func(includeNs string) telemetryv1alpha1.MetricPipelineInput { + return testutils.BuildMetricPipelineRuntimeInput(testutils.IncludeNamespaces(includeNs)) + }, + generatorBuilder: func(ns string) []client.Object { + generator := prommetricgen.New(ns) + + return []client.Object{ + generator.Pod().WithPrometheusAnnotations(prommetricgen.SchemeHTTP).K8sObject(), + generator.Service().WithPrometheusAnnotations(prommetricgen.SchemeHTTP).K8sObject(), + } + }, + }, + { + label: suite.LabelMetricGatewaySetC, + inputBuilder: func(includeNs string) telemetryv1alpha1.MetricPipelineInput { + return testutils.BuildMetricPipelineOTLPInput(testutils.IncludeNamespaces(includeNs)) + }, + generatorBuilder: func(ns string) []client.Object { + return []client.Object{ + telemetrygen.NewPod(ns, telemetrygen.SignalTypeMetrics).K8sObject(), + } + }, + }, + } + + for _, tc := range tests { + t.Run(tc.label, func(t *testing.T) { + suite.RegisterTestCase(t, tc.label, suite.LabelOAuth2) + + var ( + uniquePrefix = unique.Prefix(tc.label, suite.LabelOAuth2) + pipelineName = uniquePrefix() + backendNs = uniquePrefix("backend") + genNs = uniquePrefix("gen") + ) + + oauth2server := oauth2mock.New(backendNs) + + serverCerts, _, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() + Expect(err).ToNot(HaveOccurred()) + + backend := kitbackend.New(backendNs, kitbackend.SignalTypeMetrics, + kitbackend.WithTLS(*serverCerts), + kitbackend.WithOIDCAuth(oauth2server.IssuerURL(), oauth2server.Audience()), + ) + + pipeline := testutils.NewMetricPipelineBuilder(). + WithName(pipelineName). + WithInput(tc.inputBuilder(genNs)). + WithOTLPOutput( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPOAuth2( + testutils.OAuth2ClientID("the-mock-does-not-verify"), + testutils.OAuth2ClientSecret("the-mock-does-not-verify"), + testutils.OAuth2TokenURL(oauth2server.TokenEndpoint()), + testutils.OAuth2Params(map[string]string{"grant_type": "client_credentials"}), + ), + testutils.OTLPClientTLSFromString(serverCerts.CaCertPem.String()), + ). + Build() + + resources := []client.Object{ + kitk8sobjects.NewNamespace(backendNs).K8sObject(), + kitk8sobjects.NewNamespace(genNs).K8sObject(), + &pipeline, + } + resources = append(resources, tc.generatorBuilder(genNs)...) + resources = append(resources, oauth2server.K8sObjects()...) + resources = append(resources, backend.K8sObjects()...) + + Expect(kitk8s.CreateObjects(t, resources...)).To(Succeed()) + + assert.DeploymentReady(t, oauth2server.NamespacedName()) + assert.BackendReachable(t, backend) + assert.DeploymentReady(t, kitkyma.MetricGatewayName) + + if suite.ExpectAgent(tc.label) { + assert.DaemonSetReady(t, kitkyma.MetricAgentName) + } + + assert.MetricPipelineHealthy(t, pipelineName) + + if suite.ExpectAgent(tc.label) { + assert.MetricsFromNamespaceDelivered(t, backend, genNs, runtime.DefaultMetricsNames) + + agentMetricsURL := suite.ProxyClient.ProxyURLForService(kitkyma.MetricAgentMetricsService.Namespace, kitkyma.MetricAgentMetricsService.Name, "metrics", ports.Metrics) + assert.EmitsOTelCollectorMetrics(t, agentMetricsURL) + } else { + assert.MetricsFromNamespaceDelivered(t, backend, genNs, telemetrygen.MetricNames) + + gatewayMetricsURL := suite.ProxyClient.ProxyURLForService(kitkyma.MetricGatewayMetricsService.Namespace, kitkyma.MetricGatewayMetricsService.Name, "metrics", ports.Metrics) + assert.EmitsOTelCollectorMetrics(t, gatewayMetricsURL) + } + }) + } +} diff --git a/test/e2e/metrics/shared/secret_rotation_test.go b/test/e2e/metrics/shared/secret_rotation_test.go index 77c211b001..60847e204d 100644 --- a/test/e2e/metrics/shared/secret_rotation_test.go +++ b/test/e2e/metrics/shared/secret_rotation_test.go @@ -108,7 +108,7 @@ func TestSecretRotation(t *testing.T) { assert.MetricsFromNamespaceNotDelivered(t, backend, genNs) // Update the secret to have the correct backend endpoint - secret.UpdateSecret(kitk8sobjects.WithStringData(endpointKey, backend.Endpoint())) + secret.UpdateSecret(kitk8sobjects.WithStringData(endpointKey, backend.EndpointHTTP())) Expect(kitk8s.UpdateObjects(t, secret.K8sObject())).To(Succeed()) assert.DeploymentReady(t, kitkyma.MetricGatewayName) diff --git a/test/e2e/metrics/shared/single_pipeline_test.go b/test/e2e/metrics/shared/single_pipeline_test.go index d99d18173b..a34689e6d7 100644 --- a/test/e2e/metrics/shared/single_pipeline_test.go +++ b/test/e2e/metrics/shared/single_pipeline_test.go @@ -69,7 +69,7 @@ func TestSinglePipeline(t *testing.T) { pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/metrics/shared/single_pipeline_v1beta1_test.go b/test/e2e/metrics/shared/single_pipeline_v1beta1_test.go index 96bbb7991b..2cf72775df 100644 --- a/test/e2e/metrics/shared/single_pipeline_v1beta1_test.go +++ b/test/e2e/metrics/shared/single_pipeline_v1beta1_test.go @@ -78,7 +78,7 @@ func TestSinglePipelineV1Beta1(t *testing.T) { Output: telemetryv1beta1.MetricPipelineOutput{ OTLP: &telemetryv1beta1.OTLPOutput{ Endpoint: telemetryv1beta1.ValueType{ - Value: backend.Endpoint(), + Value: backend.EndpointHTTP(), }, }, }, diff --git a/test/e2e/metrics/shared/transform_test.go b/test/e2e/metrics/shared/transform_test.go index 1101057847..f3f9139cf0 100644 --- a/test/e2e/metrics/shared/transform_test.go +++ b/test/e2e/metrics/shared/transform_test.go @@ -176,7 +176,7 @@ func TestTransform(t *testing.T) { WithName(pipelineName). WithInput(tc.inputBuilder(genNs)). WithTransform(tc.transformSpec). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/misc/custom_label_annotation_test.go b/test/e2e/misc/custom_label_annotation_test.go index 95b7bb3016..508fe304c2 100644 --- a/test/e2e/misc/custom_label_annotation_test.go +++ b/test/e2e/misc/custom_label_annotation_test.go @@ -36,7 +36,7 @@ func TestLabelAnnotation(t *testing.T) { p := testutils.NewLogPipelineBuilder(). WithName("custom-otel-log-agent"). WithInput(testutils.BuildLogPipelineApplicationInput(testutils.ExtIncludeNamespaces(includeNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -110,7 +110,7 @@ func TestLabelAnnotation(t *testing.T) { p := testutils.NewMetricPipelineBuilder(). WithName("custom-metric-agent"). WithPrometheusInput(true, testutils.IncludeNamespaces(includeNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -155,7 +155,7 @@ func TestLabelAnnotation(t *testing.T) { pipeline: func(includeNs string, backend *kitbackend.Backend) client.Object { p := testutils.NewTracePipelineBuilder(). WithName("custom-trace"). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p diff --git a/test/e2e/misc/telemetry_log_analysis_test.go b/test/e2e/misc/telemetry_log_analysis_test.go index e209074b57..7f269de751 100644 --- a/test/e2e/misc/telemetry_log_analysis_test.go +++ b/test/e2e/misc/telemetry_log_analysis_test.go @@ -44,7 +44,7 @@ func TestTelemetryLogs(t *testing.T) { traceBackend := kitbackend.New(traceBackendNs, kitbackend.SignalTypeTraces) tracePipeline := testutils.NewTracePipelineBuilder(). WithName(tracePipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(traceBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(traceBackend.EndpointHTTP())). Build() metricBackend := kitbackend.New(metricBackendNs, kitbackend.SignalTypeMetrics) @@ -54,7 +54,7 @@ func TestTelemetryLogs(t *testing.T) { WithRuntimeInput(true, testutils.IncludeNamespaces(genMetricNs)). WithIstioInput(true, testutils.IncludeNamespaces(genMetricNs)). WithOTLPOutput( - testutils.OTLPEndpoint(metricBackend.Endpoint()), + testutils.OTLPEndpoint(metricBackend.EndpointHTTP()), ).Build() fluentBitLogBackend := kitbackend.New(fbluentBitLogBackendNs, kitbackend.SignalTypeLogsFluentBit) @@ -70,7 +70,7 @@ func TestTelemetryLogs(t *testing.T) { WithName(logPipelineName). WithOTLPInput(true). WithApplicationInput(true). - WithOTLPOutput(testutils.OTLPEndpoint(logBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(logBackend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/misc/telemetry_test.go b/test/e2e/misc/telemetry_test.go index 24ecc384ee..f6778965c4 100644 --- a/test/e2e/misc/telemetry_test.go +++ b/test/e2e/misc/telemetry_test.go @@ -60,7 +60,14 @@ func TestTelemetry(t *testing.T) { Expect(kitk8s.CreateObjects(t, resources...)).To(Succeed()) - Eventually(func(g Gomega) { + assertTelemtryCRExistsAndHasCorrectEndpointsInStatus(logGRPCEndpoint, logHTTPEndpoint, traceGRPCEndpoint, traceHTTPEndpoint, metricGRPCEndpoint, metricHTTPEndpoint) + assertValidatingWebhookConfiguration() + assertWebhookCA() + assertWebhookSecretReconcilation() +} + +func assertTelemtryCRExistsAndHasCorrectEndpointsInStatus(logGRPCEndpoint string, logHTTPEndpoint string, traceGRPCEndpoint string, traceHTTPEndpoint string, metricGRPCEndpoint string, metricHTTPEndpoint string) bool { + return Eventually(func(g Gomega) { var telemetry operatorv1alpha1.Telemetry g.Expect(suite.K8sClient.Get(suite.Ctx, kitkyma.TelemetryName, &telemetry)).Should(Succeed()) @@ -76,10 +83,6 @@ func TestTelemetry(t *testing.T) { g.Expect(telemetry.Status.Endpoints.Metrics.GRPC).Should(Equal(metricGRPCEndpoint)) g.Expect(telemetry.Status.Endpoints.Metrics.HTTP).Should(Equal(metricHTTPEndpoint)) }, periodic.EventuallyTimeout, periodic.DefaultInterval).Should(Succeed()) - - assertValidatingWebhookConfiguration() - assertWebhookCA() - assertWebhookSecretReconcilation() } func TestTelemetryWarning(t *testing.T) { diff --git a/test/e2e/traces/enrichment_values_empty_test.go b/test/e2e/traces/enrichment_values_empty_test.go index 5be4626489..814a8bca84 100644 --- a/test/e2e/traces/enrichment_values_empty_test.go +++ b/test/e2e/traces/enrichment_values_empty_test.go @@ -31,7 +31,7 @@ func TestEnrichmentValuesEmpty(t *testing.T) { backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() // All attributes in the enrichment flow are set to empty values diff --git a/test/e2e/traces/enrichment_values_predefined_test.go b/test/e2e/traces/enrichment_values_predefined_test.go index 178f8336f1..21c03e8cde 100644 --- a/test/e2e/traces/enrichment_values_predefined_test.go +++ b/test/e2e/traces/enrichment_values_predefined_test.go @@ -31,7 +31,7 @@ func TestEnrichmentValuesPredefined(t *testing.T) { backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() // All attributes in the enrichment flow are set to predefined values diff --git a/test/e2e/traces/extract_labels_test.go b/test/e2e/traces/extract_labels_test.go index 65d35a7b51..836e547fb9 100644 --- a/test/e2e/traces/extract_labels_test.go +++ b/test/e2e/traces/extract_labels_test.go @@ -50,7 +50,7 @@ func TestExtractLabels(t *testing.T) { pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() genLabels := map[string]string{ diff --git a/test/e2e/traces/filter_test.go b/test/e2e/traces/filter_test.go index f824cda2fc..a9633c1181 100644 --- a/test/e2e/traces/filter_test.go +++ b/test/e2e/traces/filter_test.go @@ -32,7 +32,7 @@ func TestFilter(t *testing.T) { backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). WithTransform(telemetryv1alpha1.TransformSpec{ Statements: []string{"set(span.attributes[\"test\"], \"passed\")"}, }). diff --git a/test/e2e/traces/mtls_about_to_expire_cert_test.go b/test/e2e/traces/mtls_about_to_expire_cert_test.go index feb5e9778c..9d9571e6dc 100644 --- a/test/e2e/traces/mtls_about_to_expire_cert_test.go +++ b/test/e2e/traces/mtls_about_to_expire_cert_test.go @@ -21,7 +21,7 @@ import ( ) func TestMTLSAboutToExpireCert(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelTraces) + suite.RegisterTestCase(t, suite.LabelTraces, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -35,13 +35,13 @@ func TestMTLSAboutToExpireCert(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCerts.CaCertPem.String(), clientCerts.ClientCertPem.String(), clientCerts.ClientKeyPem.String(), diff --git a/test/e2e/traces/mtls_cert_key_pair_dont_match_test.go b/test/e2e/traces/mtls_cert_key_pair_dont_match_test.go index 2b29465896..6276bb8aae 100644 --- a/test/e2e/traces/mtls_cert_key_pair_dont_match_test.go +++ b/test/e2e/traces/mtls_cert_key_pair_dont_match_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSCertKeyPairDontMatch(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelTraces) + suite.RegisterTestCase(t, suite.LabelTraces, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -32,13 +32,13 @@ func TestMTLSCertKeyPairDontMatch(t *testing.T) { _, clientCertsCreatedAgain, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithTLS(*serverCertsDefault)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithMTLS(*serverCertsDefault)) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCertsDefault.CaCertPem.String(), clientCertsDefault.ClientCertPem.String(), clientCertsCreatedAgain.ClientKeyPem.String(), // Use different key diff --git a/test/e2e/traces/mtls_expired_cert_test.go b/test/e2e/traces/mtls_expired_cert_test.go index d879a7149e..5e8302ecef 100644 --- a/test/e2e/traces/mtls_expired_cert_test.go +++ b/test/e2e/traces/mtls_expired_cert_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSExpiredCert(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelTraces) + suite.RegisterTestCase(t, suite.LabelTraces, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSExpiredCert(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithTLS(*expiredServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithMTLS(*expiredServerCerts)) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( expiredClientCerts.CaCertPem.String(), expiredClientCerts.ClientCertPem.String(), expiredClientCerts.ClientKeyPem.String(), diff --git a/test/e2e/traces/mtls_invalid_ca_test.go b/test/e2e/traces/mtls_invalid_ca_test.go index 7af7e60bce..f1166af347 100644 --- a/test/e2e/traces/mtls_invalid_ca_test.go +++ b/test/e2e/traces/mtls_invalid_ca_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSInvalidCA(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelTraces) + suite.RegisterTestCase(t, suite.LabelTraces, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSInvalidCA(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithTLS(*invalidServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithMTLS(*invalidServerCerts)) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( invalidClientCerts.CaCertPem.String(), invalidClientCerts.ClientCertPem.String(), invalidClientCerts.ClientKeyPem.String(), diff --git a/test/e2e/traces/mtls_invalid_cert_test.go b/test/e2e/traces/mtls_invalid_cert_test.go index 018b4f7c98..833982a303 100644 --- a/test/e2e/traces/mtls_invalid_cert_test.go +++ b/test/e2e/traces/mtls_invalid_cert_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLSInvalidCert(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelTraces) + suite.RegisterTestCase(t, suite.LabelTraces, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -31,13 +31,13 @@ func TestMTLSInvalidCert(t *testing.T) { Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithTLS(*invalidServerCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithMTLS(*invalidServerCerts)) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( invalidClientCerts.CaCertPem.String(), invalidClientCerts.ClientCertPem.String(), invalidClientCerts.ClientKeyPem.String(), diff --git a/test/e2e/traces/mtls_test.go b/test/e2e/traces/mtls_test.go index be46aa510c..7711d053dc 100644 --- a/test/e2e/traces/mtls_test.go +++ b/test/e2e/traces/mtls_test.go @@ -18,7 +18,7 @@ import ( ) func TestMTLS(t *testing.T) { - suite.RegisterTestCase(t, suite.LabelTraces) + suite.RegisterTestCase(t, suite.LabelTraces, suite.LabelMTLS) var ( uniquePrefix = unique.Prefix() @@ -30,13 +30,13 @@ func TestMTLS(t *testing.T) { serverCerts, clientCerts, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() Expect(err).ToNot(HaveOccurred()) - backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithTLS(*serverCerts)) + backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, kitbackend.WithMTLS(*serverCerts)) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). WithOTLPOutput( - testutils.OTLPEndpoint(backend.Endpoint()), - testutils.OTLPClientTLSFromString( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPClientMTLSFromString( clientCerts.CaCertPem.String(), clientCerts.ClientCertPem.String(), clientCerts.ClientKeyPem.String(), diff --git a/test/e2e/traces/multi_pipeline_broken_test.go b/test/e2e/traces/multi_pipeline_broken_test.go index e1fa23f00e..46bbd4cb8f 100644 --- a/test/e2e/traces/multi_pipeline_broken_test.go +++ b/test/e2e/traces/multi_pipeline_broken_test.go @@ -34,7 +34,7 @@ func TestMultiPipelineBroken(t *testing.T) { healthyPipeline := testutils.NewTracePipelineBuilder(). WithName(healthyPipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() brokenPipeline := testutils.NewTracePipelineBuilder(). diff --git a/test/e2e/traces/multi_pipeline_fanout_test.go b/test/e2e/traces/multi_pipeline_fanout_test.go index 21b5c3d0e1..2d3c3d7258 100644 --- a/test/e2e/traces/multi_pipeline_fanout_test.go +++ b/test/e2e/traces/multi_pipeline_fanout_test.go @@ -33,12 +33,12 @@ func TestMultiPipelineFanout(t *testing.T) { pipeline1 := testutils.NewTracePipelineBuilder(). WithName(pipeline1Name). - WithOTLPOutput(testutils.OTLPEndpoint(backend1.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend1.EndpointHTTP())). Build() pipeline2 := testutils.NewTracePipelineBuilder(). WithName(pipeline2Name). - WithOTLPOutput(testutils.OTLPEndpoint(backend2.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend2.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/traces/multi_pipeline_max_pipeline_test.go b/test/e2e/traces/multi_pipeline_max_pipeline_test.go index 7e47367d8c..4816a3c91e 100644 --- a/test/e2e/traces/multi_pipeline_max_pipeline_test.go +++ b/test/e2e/traces/multi_pipeline_max_pipeline_test.go @@ -42,14 +42,14 @@ func TestMultiPipelineMaxPipeline(t *testing.T) { pipelineName := fmt.Sprintf("%s-%d", pipelineBase, i) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() pipelines = append(pipelines, &pipeline) } additionalPipeline := testutils.NewTracePipelineBuilder(). WithName(additionalPipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/traces/noisy_span_filter_test.go b/test/e2e/traces/noisy_span_filter_test.go index 34426235fb..7af7bd44d3 100644 --- a/test/e2e/traces/noisy_span_filter_test.go +++ b/test/e2e/traces/noisy_span_filter_test.go @@ -47,7 +47,7 @@ func TestNoisyFilters(t *testing.T) { pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() regularSpansGen := telemetrygen.NewPod(regularSpansNs, telemetrygen.SignalTypeTraces).K8sObject() diff --git a/test/e2e/traces/oauth2_test.go b/test/e2e/traces/oauth2_test.go new file mode 100644 index 0000000000..15f7fd3822 --- /dev/null +++ b/test/e2e/traces/oauth2_test.go @@ -0,0 +1,74 @@ +package traces + +import ( + "testing" + + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/kyma-project/telemetry-manager/internal/otelcollector/ports" + testutils "github.com/kyma-project/telemetry-manager/internal/utils/test" + "github.com/kyma-project/telemetry-manager/test/testkit/assert" + kitk8s "github.com/kyma-project/telemetry-manager/test/testkit/k8s" + kitk8sobjects "github.com/kyma-project/telemetry-manager/test/testkit/k8s/objects" + kitkyma "github.com/kyma-project/telemetry-manager/test/testkit/kyma" + kitbackend "github.com/kyma-project/telemetry-manager/test/testkit/mocks/backend" + "github.com/kyma-project/telemetry-manager/test/testkit/mocks/oauth2mock" + "github.com/kyma-project/telemetry-manager/test/testkit/mocks/telemetrygen" + "github.com/kyma-project/telemetry-manager/test/testkit/suite" + "github.com/kyma-project/telemetry-manager/test/testkit/unique" +) + +func TestOAuth2(t *testing.T) { + suite.RegisterTestCase(t, suite.LabelTraces, suite.LabelOAuth2) + + var ( + uniquePrefix = unique.Prefix() + pipelineName = uniquePrefix() + backendNs = uniquePrefix("backend") + genNs = uniquePrefix("gen") + ) + + oauth2server := oauth2mock.New(backendNs) + + serverCerts, _, err := testutils.NewCertBuilder(kitbackend.DefaultName, backendNs).Build() + Expect(err).ToNot(HaveOccurred()) + + backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces, + kitbackend.WithTLS(*serverCerts), + kitbackend.WithOIDCAuth(oauth2server.IssuerURL(), oauth2server.Audience()), + ) + pipeline := testutils.NewTracePipelineBuilder(). + WithName(pipelineName). + WithOTLPOutput( + testutils.OTLPEndpoint(backend.EndpointHTTPS()), + testutils.OTLPOAuth2( + testutils.OAuth2ClientID("the-mock-does-not-verify"), + testutils.OAuth2ClientSecret("the-mock-does-not-verify"), + testutils.OAuth2TokenURL(oauth2server.TokenEndpoint()), + testutils.OAuth2Params(map[string]string{"grant_type": "client_credentials"}), + ), + testutils.OTLPClientTLSFromString(serverCerts.CaCertPem.String()), + ). + Build() + + resources := []client.Object{ + kitk8sobjects.NewNamespace(backendNs).K8sObject(), + kitk8sobjects.NewNamespace(genNs).K8sObject(), + &pipeline, + telemetrygen.NewPod(genNs, telemetrygen.SignalTypeTraces).K8sObject(), + } + resources = append(resources, backend.K8sObjects()...) + resources = append(resources, oauth2server.K8sObjects()...) + + Expect(kitk8s.CreateObjects(t, resources...)).To(Succeed()) + + assert.DeploymentReady(t, oauth2server.NamespacedName()) + assert.BackendReachable(t, backend) + assert.DeploymentReady(t, kitkyma.TraceGatewayName) + assert.TracePipelineHealthy(t, pipelineName) + assert.TracesFromNamespaceDelivered(t, backend, genNs) + + gatewayMetricsURL := suite.ProxyClient.ProxyURLForService(kitkyma.TraceGatewayMetricsService.Namespace, kitkyma.TraceGatewayMetricsService.Name, "metrics", ports.Metrics) + assert.EmitsOTelCollectorMetrics(t, gatewayMetricsURL) +} diff --git a/test/e2e/traces/reject_creation_test.go b/test/e2e/traces/reject_creation_test.go index 7e8853b9c3..53af4da6d7 100644 --- a/test/e2e/traces/reject_creation_test.go +++ b/test/e2e/traces/reject_creation_test.go @@ -7,7 +7,6 @@ import ( . "github.com/onsi/gomega" apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" telemetryv1alpha1 "github.com/kyma-project/telemetry-manager/apis/telemetry/v1alpha1" @@ -25,18 +24,16 @@ func TestRejectTracePipelineCreation(t *testing.T) { var backenEndpoint = backendHost + ":" + strconv.Itoa(backendPort) tests := []struct { + name string pipeline telemetryv1alpha1.TracePipeline errorMsg string field string causes int - label string }{ // output general { + name: "no-output", pipeline: telemetryv1alpha1.TracePipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "no-output", - }, Spec: telemetryv1alpha1.TracePipelineSpec{}, }, errorMsg: "must be of type object", @@ -44,10 +41,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { causes: 2, }, { + name: "valuefrom-accepts-only-one-option", pipeline: telemetryv1alpha1.TracePipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "valuefrom-accepts-only-one-option", - }, Spec: telemetryv1alpha1.TracePipelineSpec{ Output: telemetryv1alpha1.TracePipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -69,10 +64,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint", }, { + name: "secretkeyref-requires-key", pipeline: telemetryv1alpha1.TracePipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-key", - }, Spec: telemetryv1alpha1.TracePipelineSpec{ Output: telemetryv1alpha1.TracePipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -92,10 +85,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint.valueFrom.secretKeyRef.key", }, { + name: "secretkeyref-requires-namespace", pipeline: telemetryv1alpha1.TracePipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-namespace", - }, Spec: telemetryv1alpha1.TracePipelineSpec{ Output: telemetryv1alpha1.TracePipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -115,10 +106,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp.endpoint.valueFrom.secretKeyRef.namespace", }, { + name: "secretkeyref-requires-name", pipeline: telemetryv1alpha1.TracePipeline{ - ObjectMeta: metav1.ObjectMeta{ - Name: "secretkeyref-requires-name", - }, Spec: telemetryv1alpha1.TracePipelineSpec{ Output: telemetryv1alpha1.TracePipelineOutput{ OTLP: &telemetryv1alpha1.OTLPOutput{ @@ -139,8 +128,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { }, // otlp output { + name: "otlp-output-with-default-proto-and-path", pipeline: testutils.NewTracePipelineBuilder(). - WithName("otlp-output-with-default-proto-and-path"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPEndpointPath("/v1/dummy"), @@ -150,8 +139,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp", }, { + name: "otlp-output-with-grpc-proto-and-path", pipeline: testutils.NewTracePipelineBuilder(). - WithName("otlp-output-with-grpc-proto-and-path"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPEndpointPath("/v1/dummy"), @@ -162,8 +151,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp", }, { + name: "otlp-output-with-non-valid-proto", pipeline: testutils.NewTracePipelineBuilder(). - WithName("otlp-output-with-non-valid-proto"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPProtocol("icke"), @@ -174,8 +163,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp.protocol", }, { + name: "otlp-output-basic-auth-secretref-missing-password-key", pipeline: testutils.NewTracePipelineBuilder(). - WithName("otlp-output-basic-auth-secretref-missing-password-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPBasicAuthFromSecret("name", "namespace", "user", ""), @@ -185,8 +174,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp.authentication.basic.password.valueFrom.secretKeyRef.key", }, { + name: "otlp-output-basic-auth-secretref-missing-user-key", pipeline: testutils.NewTracePipelineBuilder(). - WithName("otlp-output-basic-auth-secretref-missing-user-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPBasicAuthFromSecret("name", "namespace", "", "password"), @@ -196,8 +185,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp.authentication.basic.user.valueFrom.secretKeyRef.key", }, { + name: "otlp-output-tls-missing-key", pipeline: testutils.NewTracePipelineBuilder(). - WithName("otlp-output-tls-missing-key"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ @@ -210,8 +199,8 @@ func TestRejectTracePipelineCreation(t *testing.T) { field: "spec.output.otlp.tls", }, { + name: "otlp-output-tls-missing-cert", pipeline: testutils.NewTracePipelineBuilder(). - WithName("otlp-output-tls-missing-cert"). WithOTLPOutput( testutils.OTLPEndpoint(backenEndpoint), testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ @@ -223,11 +212,60 @@ func TestRejectTracePipelineCreation(t *testing.T) { errorMsg: "Can define either both 'cert' and 'key', or neither", field: "spec.output.otlp.tls", }, + { + name: "otlp-output-oauth2-invalid-token-url", + pipeline: testutils.NewTracePipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2ClientID("clientid"), + testutils.OAuth2TokenURL("../not-a-url"), + ), + ). + Build(), + errorMsg: "Invalid value: \"object\": 'tokenURL' must be a valid URL", + field: "spec.output.otlp.authentication.oauth2.tokenURL", + }, + { + name: "otlp-output-oauth2-missing-client-id", + pipeline: testutils.NewTracePipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2TokenURL("https://auth.example.com/token"), + ), + ). + Build(), + errorMsg: "Invalid value: \"object\": no such key: value evaluating rule: 'clientID' missing", + field: "spec.output.otlp.authentication.oauth2.clientID", + }, + { + name: "otlp-output-oauth2-insecure", + pipeline: testutils.NewTracePipelineBuilder(). + WithOTLPOutput( + testutils.OTLPEndpoint(backenEndpoint), + testutils.OTLPOAuth2( + testutils.OAuth2ClientID("clientid"), + testutils.OAuth2ClientSecret("clientsecret"), + testutils.OAuth2TokenURL("https://auth.example.com/token"), + ), + testutils.OTLPClientTLS(&telemetryv1alpha1.OTLPTLS{ + Insecure: true, + }), + ). + Build(), + errorMsg: "OAuth2 authentication requires TLS when using gRPC protocol", + field: "spec.output.otlp", + }, } for _, tc := range tests { - t.Run(suite.LabelMisc, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { suite.RegisterTestCase(t, suite.LabelMisc) + tc.pipeline.Name = tc.name + resources := []client.Object{&tc.pipeline} err := kitk8s.CreateObjects(t, resources...) diff --git a/test/e2e/traces/secret_rotation_test.go b/test/e2e/traces/secret_rotation_test.go index 23dea8eb19..da373ebb21 100644 --- a/test/e2e/traces/secret_rotation_test.go +++ b/test/e2e/traces/secret_rotation_test.go @@ -64,7 +64,7 @@ func TestSecretRotation(t *testing.T) { assert.TracesFromNamespacesNotDelivered(t, backend, []string{genNs}) // Update the secret to have the correct backend endpoint - secret.UpdateSecret(kitk8sobjects.WithStringData(endpointKey, backend.Endpoint())) + secret.UpdateSecret(kitk8sobjects.WithStringData(endpointKey, backend.EndpointHTTP())) Expect(kitk8s.UpdateObjects(t, secret.K8sObject())).To(Succeed()) assert.DeploymentReady(t, kitkyma.TraceGatewayName) diff --git a/test/e2e/traces/service_name_test.go b/test/e2e/traces/service_name_test.go index 886fd31aa7..4e4cbd32d4 100644 --- a/test/e2e/traces/service_name_test.go +++ b/test/e2e/traces/service_name_test.go @@ -40,7 +40,7 @@ func TestServiceName(t *testing.T) { pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() podSpecWithUndefinedService := telemetrygen.PodSpec(telemetrygen.SignalTypeTraces, diff --git a/test/e2e/traces/single_pipeline_test.go b/test/e2e/traces/single_pipeline_test.go index fd7c396842..9e12891930 100644 --- a/test/e2e/traces/single_pipeline_test.go +++ b/test/e2e/traces/single_pipeline_test.go @@ -31,7 +31,7 @@ func TestSinglePipeline(t *testing.T) { backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/traces/single_pipeline_v1beta1_test.go b/test/e2e/traces/single_pipeline_v1beta1_test.go index e81cad94b1..8835536ebc 100644 --- a/test/e2e/traces/single_pipeline_v1beta1_test.go +++ b/test/e2e/traces/single_pipeline_v1beta1_test.go @@ -38,7 +38,7 @@ func TestSinglePipelineV1Beta1(t *testing.T) { Output: telemetryv1beta1.TracePipelineOutput{ OTLP: &telemetryv1beta1.OTLPOutput{ Endpoint: telemetryv1beta1.ValueType{ - Value: backend.Endpoint(), + Value: backend.EndpointHTTP(), }, }, }, diff --git a/test/e2e/traces/transform_test.go b/test/e2e/traces/transform_test.go index 4a0a6f8221..742cf11791 100644 --- a/test/e2e/traces/transform_test.go +++ b/test/e2e/traces/transform_test.go @@ -83,7 +83,7 @@ func TestTransform(t *testing.T) { backend := kitbackend.New(backendNs, kitbackend.SignalTypeTraces) pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). WithTransform(tt.transformSpec). Build() diff --git a/test/e2e/upgrade/logs_upgrade_test.go b/test/e2e/upgrade/logs_upgrade_test.go index c0ea40169d..02d4d7522e 100644 --- a/test/e2e/upgrade/logs_upgrade_test.go +++ b/test/e2e/upgrade/logs_upgrade_test.go @@ -32,7 +32,7 @@ func TestLogsUpgrade(t *testing.T) { pipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/upgrade/metrics_upgrade_test.go b/test/e2e/upgrade/metrics_upgrade_test.go index 58efc74e9e..afa413a170 100644 --- a/test/e2e/upgrade/metrics_upgrade_test.go +++ b/test/e2e/upgrade/metrics_upgrade_test.go @@ -32,7 +32,7 @@ func TestMetricsUpgrade(t *testing.T) { pipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/e2e/upgrade/traces_upgrade_test.go b/test/e2e/upgrade/traces_upgrade_test.go index f47617e0d8..fef1d92c18 100644 --- a/test/e2e/upgrade/traces_upgrade_test.go +++ b/test/e2e/upgrade/traces_upgrade_test.go @@ -32,7 +32,7 @@ func TestTracesUpgrade(t *testing.T) { pipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/integration/istio/access_logs_otlp_test.go b/test/integration/istio/access_logs_otlp_test.go index d59908be44..863ac2a18a 100644 --- a/test/integration/istio/access_logs_otlp_test.go +++ b/test/integration/istio/access_logs_otlp_test.go @@ -41,7 +41,7 @@ func TestAccessLogsOTLP(t *testing.T) { logPipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithApplicationInput(false). - WithOTLPOutput(testutils.OTLPEndpoint(logBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(logBackend.EndpointHTTP())). Build() sampleApp := prommetricgen.New(permissiveNs, prommetricgen.WithName(uniquePrefix("otlp-access-log-emitter"))) @@ -49,7 +49,7 @@ func TestAccessLogsOTLP(t *testing.T) { tracePipeline := testutils.NewTracePipelineBuilder(). WithName(pipelineName). - WithOTLPOutput(testutils.OTLPEndpoint(traceBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(traceBackend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/integration/istio/metrics_envoy_multi_pipeline_test.go b/test/integration/istio/metrics_envoy_multi_pipeline_test.go index e237a220c1..73e3eef026 100644 --- a/test/integration/istio/metrics_envoy_multi_pipeline_test.go +++ b/test/integration/istio/metrics_envoy_multi_pipeline_test.go @@ -36,14 +36,14 @@ func TestMetricsEnvoyMultiPipeline(t *testing.T) { WithName("pipeline-envoy"). WithIstioInput(true, testutils.IncludeNamespaces(app1Ns)). WithIstioInputEnvoyMetrics(true). - WithOTLPOutput(testutils.OTLPEndpoint(backend1.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend1.EndpointHTTP())). Build() pipelineExcludeApp1Ns := testutils.NewMetricPipelineBuilder(). WithName("pipeline-non-envoy"). WithIstioInput(true, testutils.ExcludeNamespaces(app1Ns)). WithIstioInputEnvoyMetrics(false). - WithOTLPOutput(testutils.OTLPEndpoint(backend2.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend2.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/integration/istio/metrics_istio_input_envoy_test.go b/test/integration/istio/metrics_istio_input_envoy_test.go index bdcaca671c..80bfa0ad74 100644 --- a/test/integration/istio/metrics_istio_input_envoy_test.go +++ b/test/integration/istio/metrics_istio_input_envoy_test.go @@ -39,7 +39,7 @@ func TestMetricsIstioInputEnvoy(t *testing.T) { WithName(pipelineName). WithIstioInput(true, testutils.IncludeNamespaces(app1Ns)). WithIstioInputEnvoyMetrics(true). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/integration/istio/metrics_istio_input_test.go b/test/integration/istio/metrics_istio_input_test.go index 8a8cc99516..0bc273451c 100644 --- a/test/integration/istio/metrics_istio_input_test.go +++ b/test/integration/istio/metrics_istio_input_test.go @@ -83,13 +83,13 @@ func TestMetricsIstioInput(t *testing.T) { WithName(pipelineName). WithOTLPInput(false). WithIstioInput(true, testutils.IncludeNamespaces(app1Ns)). - WithOTLPOutput(testutils.OTLPEndpoint(metricBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(metricBackend.EndpointHTTP())). Build() logPipeline := testutils.NewLogPipelineBuilder(). WithName(pipelineName). WithApplicationInput(false). - WithOTLPOutput(testutils.OTLPEndpoint(logBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(logBackend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/integration/istio/metrics_istio_same_port_test.go b/test/integration/istio/metrics_istio_same_port_test.go index 16c98205f1..acac5fd175 100644 --- a/test/integration/istio/metrics_istio_same_port_test.go +++ b/test/integration/istio/metrics_istio_same_port_test.go @@ -34,13 +34,13 @@ func TestMetricsIstioSamePort(t *testing.T) { metricPipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithPrometheusInput(true). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() istiofiedMetricPipeline := testutils.NewMetricPipelineBuilder(). WithName(istiofiedPipelineName). WithPrometheusInput(true). - WithOTLPOutput(testutils.OTLPEndpoint(istiofiedBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(istiofiedBackend.EndpointHTTP())). Build() // generators to use the same ports as the backends => test istio communication diff --git a/test/integration/istio/metrics_otlp_input_test.go b/test/integration/istio/metrics_otlp_input_test.go index 52f9af51bc..5e656789be 100644 --- a/test/integration/istio/metrics_otlp_input_test.go +++ b/test/integration/istio/metrics_otlp_input_test.go @@ -33,12 +33,12 @@ func TestMetricsOTLPInput(t *testing.T) { metricPipeline := testutils.NewMetricPipelineBuilder(). WithName(pipeline1Name). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() metricPipelineIstiofiedBackend := testutils.NewMetricPipelineBuilder(). WithName(pipeline2Name). - WithOTLPOutput(testutils.OTLPEndpoint(istiofiedBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(istiofiedBackend.EndpointHTTP())). Build() peerAuth := kitk8sobjects.NewPeerAuthentication(kitbackend.DefaultName, istiofiedBackendNs) diff --git a/test/integration/istio/metrics_prometheus_input_test.go b/test/integration/istio/metrics_prometheus_input_test.go index e8cb8c6760..1d7f786212 100644 --- a/test/integration/istio/metrics_prometheus_input_test.go +++ b/test/integration/istio/metrics_prometheus_input_test.go @@ -42,7 +42,7 @@ func TestMetricsPrometheusInput(t *testing.T) { metricPipeline := testutils.NewMetricPipelineBuilder(). WithName(pipelineName). WithPrometheusInput(true, testutils.IncludeNamespaces(genNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() resources := []client.Object{ diff --git a/test/integration/istio/traces_routing_test.go b/test/integration/istio/traces_routing_test.go index 4a8d3c4211..9fa50c8ad7 100644 --- a/test/integration/istio/traces_routing_test.go +++ b/test/integration/istio/traces_routing_test.go @@ -48,12 +48,12 @@ func TestTracesRouting(t *testing.T) { tracePipeline := testutils.NewTracePipelineBuilder(). WithName(pipeline1Name). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() istioTracePipeline := testutils.NewTracePipelineBuilder(). WithName(pipeline2Name). - WithOTLPOutput(testutils.OTLPEndpoint(istiofiedBackend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(istiofiedBackend.EndpointHTTP())). Build() traceGatewayExternalService := kitk8sobjects.NewService("telemetry-otlp-traces-external", kitkyma.SystemNamespaceName). diff --git a/test/selfmonitor/backpressure_test.go b/test/selfmonitor/backpressure_test.go index ae45ede379..b3507e32ff 100644 --- a/test/selfmonitor/backpressure_test.go +++ b/test/selfmonitor/backpressure_test.go @@ -35,7 +35,7 @@ func TestBackpressure(t *testing.T) { p := testutils.NewLogPipelineBuilder(). WithName(suite.LabelSelfMonitorLogAgentPrefix). WithInput(testutils.BuildLogPipelineApplicationInput(testutils.ExtIncludeNamespaces(includeNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -67,7 +67,7 @@ func TestBackpressure(t *testing.T) { p := testutils.NewLogPipelineBuilder(). WithName(suite.LabelSelfMonitorLogGatewayPrefix). WithInput(testutils.BuildLogPipelineOTLPInput(testutils.IncludeNamespaces(includeNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -130,7 +130,7 @@ func TestBackpressure(t *testing.T) { pipeline: func(includeNs string, backend *kitbackend.Backend) client.Object { p := testutils.NewMetricPipelineBuilder(). WithName(suite.LabelSelfMonitorMetricGatewayPrefix). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -164,7 +164,7 @@ func TestBackpressure(t *testing.T) { p := testutils.NewMetricPipelineBuilder(). WithName(suite.LabelSelfMonitorMetricAgentPrefix). WithPrometheusInput(true, testutils.IncludeNamespaces(includeNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -198,7 +198,7 @@ func TestBackpressure(t *testing.T) { pipeline: func(includeNs string, backend *kitbackend.Backend) client.Object { p := testutils.NewTracePipelineBuilder(). WithName(suite.LabelSelfMonitorTracesPrefix). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p diff --git a/test/selfmonitor/healthy_test.go b/test/selfmonitor/healthy_test.go index 604bfaa4c6..edc153c56b 100644 --- a/test/selfmonitor/healthy_test.go +++ b/test/selfmonitor/healthy_test.go @@ -32,7 +32,7 @@ func TestHealthy(t *testing.T) { p := testutils.NewLogPipelineBuilder(). WithName(suite.LabelSelfMonitorLogAgentPrefix). WithInput(testutils.BuildLogPipelineApplicationInput(testutils.ExtIncludeNamespaces(includeNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -56,7 +56,7 @@ func TestHealthy(t *testing.T) { p := testutils.NewLogPipelineBuilder(). WithName(suite.LabelSelfMonitorLogGatewayPrefix). WithInput(testutils.BuildLogPipelineOTLPInput(testutils.IncludeNamespaces(includeNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -101,7 +101,7 @@ func TestHealthy(t *testing.T) { pipeline: func(includeNs string, backend *kitbackend.Backend) client.Object { p := testutils.NewMetricPipelineBuilder(). WithName(suite.LabelSelfMonitorMetricGatewayPrefix). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -124,7 +124,7 @@ func TestHealthy(t *testing.T) { p := testutils.NewMetricPipelineBuilder(). WithName(suite.LabelSelfMonitorMetricAgentPrefix). WithPrometheusInput(true, testutils.IncludeNamespaces(includeNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -150,7 +150,7 @@ func TestHealthy(t *testing.T) { pipeline: func(includeNs string, backend *kitbackend.Backend) client.Object { p := testutils.NewTracePipelineBuilder(). WithName(suite.LabelSelfMonitorTracesPrefix). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p diff --git a/test/selfmonitor/outage_test.go b/test/selfmonitor/outage_test.go index 1db5de5bbe..803cb3078a 100644 --- a/test/selfmonitor/outage_test.go +++ b/test/selfmonitor/outage_test.go @@ -35,7 +35,7 @@ func TestOutage(t *testing.T) { p := testutils.NewLogPipelineBuilder(). WithName(suite.LabelSelfMonitorLogAgentPrefix). WithInput(testutils.BuildLogPipelineApplicationInput(testutils.ExtIncludeNamespaces(includeNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -66,7 +66,7 @@ func TestOutage(t *testing.T) { p := testutils.NewLogPipelineBuilder(). WithName(suite.LabelSelfMonitorLogGatewayPrefix). WithInput(testutils.BuildLogPipelineOTLPInput(testutils.IncludeNamespaces(includeNs))). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -132,7 +132,7 @@ func TestOutage(t *testing.T) { pipeline: func(includeNs string, backend *kitbackend.Backend) client.Object { p := testutils.NewMetricPipelineBuilder(). WithName(suite.LabelSelfMonitorMetricGatewayPrefix). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -169,7 +169,7 @@ func TestOutage(t *testing.T) { p := testutils.NewMetricPipelineBuilder(). WithName(suite.LabelSelfMonitorMetricAgentPrefix). WithPrometheusInput(true, testutils.IncludeNamespaces(includeNs)). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p @@ -205,7 +205,7 @@ func TestOutage(t *testing.T) { pipeline: func(includeNs string, backend *kitbackend.Backend) client.Object { p := testutils.NewTracePipelineBuilder(). WithName(suite.LabelSelfMonitorTracesPrefix). - WithOTLPOutput(testutils.OTLPEndpoint(backend.Endpoint())). + WithOTLPOutput(testutils.OTLPEndpoint(backend.EndpointHTTP())). Build() return &p diff --git a/test/testkit/assert/backend.go b/test/testkit/assert/backend.go index 081c4b8c12..4a13120030 100644 --- a/test/testkit/assert/backend.go +++ b/test/testkit/assert/backend.go @@ -82,6 +82,7 @@ func BackendReachable(t *testing.T, backend *kitbackend.Backend) { func BackendDataEventuallyMatches(t *testing.T, backend *kitbackend.Backend, httpBodyMatcher types.GomegaMatcher, assertionOptions ...BackendAssertionOption) { t.Helper() + t.Logf("Asserting that backend %s/%s data eventually matches the expected condition", backend.Namespace(), backend.Name()) assertionOptions = append(assertionOptions, WithOptionalDescription(fmt.Sprintf("Backend data did not match the expected condition. Backend: %s/%s", backend.Namespace(), backend.Name()))) queryURL := suite.ProxyClient.ProxyURLForService(backend.Namespace(), backend.Name(), kitbackend.QueryPath, kitbackend.QueryPort) diff --git a/test/testkit/images.go b/test/testkit/images.go index 2a56089b45..571c45ec10 100644 --- a/test/testkit/images.go +++ b/test/testkit/images.go @@ -4,6 +4,7 @@ package testkit const ( - DefaultTelemetryGenImage = "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:v0.141.0" - DefaultOTelCollectorImage = "europe-docker.pkg.dev/kyma-project/prod/kyma-otel-collector:0.141.0-main" + DefaultTelemetryGenImage = "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:v0.141.0" + DefaultOTelCollectorContribImage = "otel/opentelemetry-collector-contrib:latest" + DefaultOTelCollectorImage = "europe-docker.pkg.dev/kyma-project/prod/kyma-otel-collector:0.141.0-main" ) diff --git a/test/testkit/mocks/backend/backend.go b/test/testkit/mocks/backend/backend.go index c6a4ceab02..b44cb3ce9f 100644 --- a/test/testkit/mocks/backend/backend.go +++ b/test/testkit/mocks/backend/backend.go @@ -44,6 +44,11 @@ const ( SignalTypeMetricsAgent = "metrics" ) +type OIDCConfig struct { + issuerURL string + audience string +} + type Backend struct { abortFaultPercentage float64 dropFromSourceLabel map[string]string @@ -52,6 +57,8 @@ type Backend struct { namespace string replicas int32 signalType SignalType + oidc *OIDCConfig + mtls bool fluentDConfigMap *fluentdConfigMapBuilder hostSecret *kitk8sobjects.Secret @@ -90,11 +97,20 @@ func (b *Backend) NamespacedName() types.NamespacedName { return types.NamespacedName{Name: b.name, Namespace: b.namespace} } -func (b *Backend) Endpoint() string { +func (b *Backend) EndpointHTTP() string { addr := net.JoinHostPort(b.Host(), strconv.Itoa(int(b.Port()))) return fmt.Sprintf("http://%s", addr) } +func (b *Backend) EndpointHTTPS() string { + addr := net.JoinHostPort(b.Host(), strconv.Itoa(int(b.Port()))) + return fmt.Sprintf("https://%s", addr) +} + +func (b *Backend) EndpointNoScheme() string { + return net.JoinHostPort(b.Host(), strconv.Itoa(int(b.Port()))) +} + func (b *Backend) Host() string { return fmt.Sprintf("%s.%s.svc.cluster.local", b.name, b.namespace) } @@ -149,6 +165,8 @@ func (b *Backend) buildResources() { exportedFilePath, b.signalType, b.certs, + b.oidc, + b.mtls, ) b.collectorDeployment = newCollectorDeployment( @@ -170,7 +188,7 @@ func (b *Backend) buildResources() { // TODO: LogPipelines requires the host and the port to be separated. // TracePipeline/MetricPipeline requires an endpoint in the format of scheme://host:port. // The referencable secret is called host in both cases, but the value is different. It has to be refactored. - host := b.Endpoint() + host := b.EndpointHTTP() if b.signalType == SignalTypeLogsFluentBit { b.fluentDConfigMap = newFluentDConfigMapBuilder( diff --git a/test/testkit/mocks/backend/collector_config_map.go b/test/testkit/mocks/backend/collector_config_map.go index 9c558572db..871dc9db02 100644 --- a/test/testkit/mocks/backend/collector_config_map.go +++ b/test/testkit/mocks/backend/collector_config_map.go @@ -1,7 +1,9 @@ package backend import ( + "bytes" "strings" + "text/template" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -15,123 +17,148 @@ type collectorConfigMapBuilder struct { exportedFilePath string signalType SignalType certs *testutils.ServerCerts + oidc *OIDCConfig + mtls bool } -func newCollectorConfigMap(name, namespace, path string, signalType SignalType, certs *testutils.ServerCerts) *collectorConfigMapBuilder { +func newCollectorConfigMap(name, namespace, path string, signalType SignalType, certs *testutils.ServerCerts, oidc *OIDCConfig, mtls bool) *collectorConfigMapBuilder { return &collectorConfigMapBuilder{ name: name, namespace: namespace, exportedFilePath: path, signalType: signalType, certs: certs, + oidc: oidc, + mtls: mtls, } } -const otelConfigTemplate = `receivers: - otlp: - protocols: - grpc: - endpoint: ${MY_POD_IP}:4317 - http: - endpoint: ${MY_POD_IP}:4318 -exporters: - file: - path: {{ FILEPATH }} -service: - telemetry: - logs: - level: "info" - pipelines: - {{ SIGNAL_TYPE }}: - receivers: - - otlp - exporters: - - file` - -const tlsConfigTemplate = `receivers: - otlp: - protocols: - grpc: - tls: - cert_pem: "{{ CERT_PEM }}" - key_pem: "{{ KEY_PEM }}" - client_ca_file: {{ CA_FILE_PATH }} - endpoint: ${MY_POD_IP}:4317 - http: - endpoint: ${MY_POD_IP}:4318 -exporters: - file: - path: {{ FILEPATH }} -service: - telemetry: - logs: - level: "info" - pipelines: - {{ SIGNAL_TYPE }}: - receivers: - - otlp - exporters: - - file` - -const logConfigTemplate = `receivers: +const unifiedConfigTemplate = ` +{{- if .OIDCEnabled }} +extensions: + oidc: + issuer_url: "{{ .IssuerURL }}" + audience: "{{ .Audience }}" +{{- end }} +receivers: + {{- if .FluentBit }} fluentforward: endpoint: localhost:8006 + {{- end }} otlp: protocols: grpc: + {{- if .UseTLS }} + tls: + cert_pem: "{{ .CertPem }}" + key_pem: "{{ .KeyPem }}" + {{- if .MTLS }} + client_ca_file: {{ .CaFilePath }} + {{- end }} + {{- end }} + {{- if .OIDCEnabled }} + auth: + authenticator: oidc + {{- end }} endpoint: ${MY_POD_IP}:4317 http: endpoint: ${MY_POD_IP}:4318 exporters: file: - path: {{ FILEPATH }} + path: {{ .FilePath }} service: telemetry: logs: level: "info" pipelines: - {{ SIGNAL_TYPE }}: + {{ .SignalType }}: receivers: - otlp + {{- if .FluentBit }} - fluentforward + {{- end }} exporters: - - file` + - file + {{- if .OIDCEnabled }} + extensions: + - oidc + {{- end }} +` func (cm *collectorConfigMapBuilder) Name() string { return cm.name } func (cm *collectorConfigMapBuilder) K8sObject() *corev1.ConfigMap { - var configTemplate string - - switch { - case cm.signalType == SignalTypeLogsFluentBit: - configTemplate = logConfigTemplate - case cm.certs != nil: - configTemplate = tlsConfigTemplate - default: - configTemplate = otelConfigTemplate - } + configTemplate := unifiedConfigTemplate - config := strings.Replace(configTemplate, "{{ FILEPATH }}", cm.exportedFilePath, 1) + // Prepare template data + signal := string(cm.signalType) if cm.signalType == SignalTypeLogsOTel { - config = strings.Replace(config, "{{ SIGNAL_TYPE }}", "logs", 1) - } else { - config = strings.Replace(config, "{{ SIGNAL_TYPE }}", string(cm.signalType), 1) + signal = "logs" + } + + isFluent := cm.signalType == SignalTypeLogsFluentBit + useTLS := cm.certs != nil && !isFluent + oidcEnabled := cm.oidc != nil + + tplData := struct { + FilePath string + SignalType string + CertPem string + KeyPem string + CaFilePath string + UseTLS bool + MTLS bool + FluentBit bool + OIDCEnabled bool + IssuerURL string + Audience string + }{ + FilePath: cm.exportedFilePath, + SignalType: signal, + CertPem: "", + KeyPem: "", + CaFilePath: "", + UseTLS: useTLS, + FluentBit: isFluent, + OIDCEnabled: false, + IssuerURL: "", + Audience: "", + MTLS: cm.mtls, + } + + if oidcEnabled { + tplData.IssuerURL = cm.oidc.issuerURL + tplData.Audience = cm.oidc.audience + tplData.OIDCEnabled = true } data := make(map[string]string) - if cm.certs != nil && cm.signalType != SignalTypeLogsFluentBit { - certPem := strings.ReplaceAll(cm.certs.ServerCertPem.String(), "\n", "\\n") - keyPem := strings.ReplaceAll(cm.certs.ServerKeyPem.String(), "\n", "\\n") - config = strings.Replace(config, "{{ CERT_PEM }}", certPem, 1) - config = strings.Replace(config, "{{ KEY_PEM }}", keyPem, 1) - config = strings.Replace(config, "{{ CA_FILE_PATH }}", "/etc/collector/ca.crt", 1) + if useTLS { + tplData.CertPem = strings.ReplaceAll(cm.certs.ServerCertPem.String(), "\n", "\\n") + tplData.KeyPem = strings.ReplaceAll(cm.certs.ServerKeyPem.String(), "\n", "\\n") + tplData.CaFilePath = "/etc/collector/ca.crt" data["ca.crt"] = cm.certs.CaCertPem.String() } + // Render template using text/template + tpl, err := template.New("collector").Parse(configTemplate) + if err != nil { + panic(err) // Template parsing should not fail + } + + var buf bytes.Buffer + + err = tpl.Execute(&buf, tplData) + if err != nil { + panic(err) // Template execution should not fail + } + + config := buf.String() + data["config.yaml"] = config return &corev1.ConfigMap{ diff --git a/test/testkit/mocks/backend/collector_deployment.go b/test/testkit/mocks/backend/collector_deployment.go index 50b1e889b6..ca4f3d22e0 100644 --- a/test/testkit/mocks/backend/collector_deployment.go +++ b/test/testkit/mocks/backend/collector_deployment.go @@ -82,7 +82,7 @@ func (d *collectorDeploymentBuilder) containers() []corev1.Container { containers := []corev1.Container{ { Name: "otel-collector", - Image: testkit.DefaultOTelCollectorImage, + Image: testkit.DefaultOTelCollectorContribImage, Args: []string{"--config=/etc/collector/config.yaml"}, SecurityContext: &corev1.SecurityContext{ RunAsUser: ptr.To[int64](101), diff --git a/test/testkit/mocks/backend/options.go b/test/testkit/mocks/backend/options.go index a5ff0a6f16..f662c53bb7 100644 --- a/test/testkit/mocks/backend/options.go +++ b/test/testkit/mocks/backend/options.go @@ -28,8 +28,25 @@ func WithReplicas(replicas int32) Option { } } -func WithTLS(certKey testutils.ServerCerts) Option { +func WithMTLS(certs testutils.ServerCerts) Option { return func(b *Backend) { - b.certs = &certKey + b.mtls = true + b.certs = &certs + } +} + +func WithTLS(certs testutils.ServerCerts) Option { + return func(b *Backend) { + b.mtls = false + b.certs = &certs + } +} + +func WithOIDCAuth(issuerURL, audience string) Option { + return func(b *Backend) { + b.oidc = &OIDCConfig{ + issuerURL: issuerURL, + audience: audience, + } } } diff --git a/test/testkit/mocks/oauth2mock/oauth2mock.go b/test/testkit/mocks/oauth2mock/oauth2mock.go new file mode 100644 index 0000000000..7c548001c1 --- /dev/null +++ b/test/testkit/mocks/oauth2mock/oauth2mock.go @@ -0,0 +1,102 @@ +package oauth2mock + +import ( + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + kitk8sobjects "github.com/kyma-project/telemetry-manager/test/testkit/k8s/objects" +) + +const ( + oauth2MockImage = "europe-central2-docker.pkg.dev/sap-se-cx-kyma-goat/networking-dev-tools/oauth2-mock:latest" + + DefaultName = "oauth2-mock" + + AudienceDefault = "default" +) + +type OAuth2Authenticator struct { + name string + namespace string + authenticatorDeployment *kitk8sobjects.Deployment + authenticatorService *kitk8sobjects.Service +} + +func New(namespace string) *OAuth2Authenticator { + auth := &OAuth2Authenticator{ + name: DefaultName, + namespace: namespace, + } + + auth.buildResources() + + return auth +} + +func (o *OAuth2Authenticator) Name() string { + return o.name +} + +func (o *OAuth2Authenticator) Namespace() string { + return o.namespace +} + +func (o *OAuth2Authenticator) NamespacedName() types.NamespacedName { + return types.NamespacedName{Name: o.name, Namespace: o.namespace} +} + +func (o *OAuth2Authenticator) Audience() string { + return AudienceDefault +} + +func (o *OAuth2Authenticator) TokenEndpoint() string { + return fmt.Sprintf("http://%s.%s.svc.cluster.local:8080/oauth2/token", o.name, o.namespace) +} + +func (o *OAuth2Authenticator) IssuerURL() string { + return fmt.Sprintf("http://%s.%s.svc.cluster.local:8080", o.name, o.namespace) +} + +func (o *OAuth2Authenticator) K8sObjects() []client.Object { + var objects []client.Object + + objects = append(objects, o.authenticatorDeployment.K8sObject()) + objects = append(objects, o.authenticatorService.K8sObject(kitk8sobjects.WithLabel("app", o.name))) + + return objects +} + +func (o *OAuth2Authenticator) buildResources() { + podSpec := corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "oauth2-mock", + Image: oauth2MockImage, + Ports: []corev1.ContainerPort{ + { + ContainerPort: 8080, + Name: "http", + }, + }, + Env: []corev1.EnvVar{ + { + Name: "iss", + Value: o.IssuerURL(), + }, + }, + }, + }, + } + o.authenticatorDeployment = kitk8sobjects.NewDeployment( + o.name, + o.namespace, + ).WithReplicas(1).WithPodSpec(podSpec).WithLabel("app", o.name) + + o.authenticatorService = kitk8sobjects.NewService( + o.name, + o.namespace, + ).WithPort("http", 8080) +} diff --git a/test/testkit/suite/suite.go b/test/testkit/suite/suite.go index 0de9a818c2..6a760a26da 100644 --- a/test/testkit/suite/suite.go +++ b/test/testkit/suite/suite.go @@ -140,6 +140,11 @@ const ( // LabelUpgrade defines the label for Upgrade tests, which preserve K8s objects between test runs. LabelUpgrade = "upgrade" + + // LabelOAuth2 defines the label for OAuth2 related tests. + LabelOAuth2 = "oauth2" + // LabelMTLS defines the label for mTLS related tests. + LabelMTLS = "mtls" ) func ExpectAgent(label string) bool { // TODO(TeodorSAP): Use this for log e2e tests as well @@ -258,6 +263,10 @@ func findLabelFilterExpression() string { func toSet(labels []string) map[string]struct{} { set := make(map[string]struct{}, len(labels)) for _, label := range labels { + if label == "" { + continue + } + set[label] = struct{}{} }