diff --git a/.chloggen/inst-tls.yaml b/.chloggen/inst-tls.yaml
new file mode 100755
index 0000000000..368bb318fe
--- /dev/null
+++ b/.chloggen/inst-tls.yaml
@@ -0,0 +1,34 @@
+# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
+change_type: enhancement
+
+# The name of the component, or a single word describing the area of concern, (e.g. collector, target allocator, auto-instrumentation, opamp, github action)
+component: auto-instrumentation
+
+# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
+note: Add support for specifying exporter TLS certificates in auto-instrumentation.
+
+# One or more tracking issues related to the change
+issues: [3338]
+
+# (Optional) One or more lines of additional information to render under the primary note.
+# These lines will be padded with 2 spaces and then inserted directly into the document.
+# Use pipe (|) for multiline entries.
+subtext: |
+ Now Instrumentation CR supports specifying TLS certificates for exporter:
+ ```yaml
+ spec:
+ exporter:
+ endpoint: https://otel-collector:4317
+ tls:
+ secretName: otel-tls-certs
+ configMapName: otel-ca-bundle
+ # otel-ca-bundle
+ ca: ca.crt
+ # present in otel-tls-certs
+ cert: tls.crt
+ # present in otel-tls-certs
+ key: tls.key
+ ```
+
+ * Propagating secrets across namespaces can be done with https://github.com/EmberStack/kubernetes-reflector or https://github.com/zakkg3/ClusterSecret
+ * Restarting workloads on certificate renewal can be done with https://github.com/stakater/Reloader or https://github.com/wave-k8s/wave
diff --git a/apis/v1alpha1/instrumentation_types.go b/apis/v1alpha1/instrumentation_types.go
index 2cccef7d6b..c76ab49d8b 100644
--- a/apis/v1alpha1/instrumentation_types.go
+++ b/apis/v1alpha1/instrumentation_types.go
@@ -97,8 +97,37 @@ type Resource struct {
// Exporter defines OTLP exporter configuration.
type Exporter struct {
// Endpoint is address of the collector with OTLP endpoint.
+ // If the endpoint defines https:// scheme TLS has to be specified.
// +optional
Endpoint string `json:"endpoint,omitempty"`
+
+ // TLS defines certificates for TLS.
+ // TLS needs to be enabled by specifying https:// scheme in the Endpoint.
+ TLS *TLS `json:"tls,omitempty"`
+}
+
+// TLS defines TLS configuration for exporter.
+type TLS struct {
+ // SecretName defines secret name that will be used to configure TLS on the exporter.
+ // It is user responsibility to create the secret in the namespace of the workload.
+ // The secret must contain client certificate (Cert) and private key (Key).
+ // The CA certificate might be defined in the secret or in the config map.
+ SecretName string `json:"secretName,omitempty"`
+
+ // ConfigMapName defines configmap name with CA certificate. If it is not defined CA certificate will be
+ // used from the secret defined in SecretName.
+ ConfigMapName string `json:"configMapName,omitempty"`
+
+ // CA defines the key of certificate (e.g. ca.crt) in the configmap map, secret or absolute path to a certificate.
+ // The absolute path can be used when certificate is already present on the workload filesystem e.g.
+ // /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt
+ CA string `json:"ca,omitempty"`
+ // Cert defines the key (e.g. tls.crt) of the client certificate in the secret or absolute path to a certificate.
+ // The absolute path can be used when certificate is already present on the workload filesystem.
+ Cert string `json:"cert,omitempty"`
+ // Key defines a key (e.g. tls.key) of the private key in the secret or absolute path to a certificate.
+ // The absolute path can be used when certificate is already present on the workload filesystem.
+ Key string `json:"key,omitempty"`
}
// Sampler defines sampling configuration.
diff --git a/apis/v1alpha1/instrumentation_webhook.go b/apis/v1alpha1/instrumentation_webhook.go
index 004992f795..3d896b0a10 100644
--- a/apis/v1alpha1/instrumentation_webhook.go
+++ b/apis/v1alpha1/instrumentation_webhook.go
@@ -236,9 +236,31 @@ func (w InstrumentationWebhook) validate(r *Instrumentation) (admission.Warnings
default:
return warnings, fmt.Errorf("spec.sampler.type is not valid: %s", r.Spec.Sampler.Type)
}
+
+ warnings = append(warnings, validateExporter(r.Spec.Exporter)...)
+
return warnings, nil
}
+func validateExporter(exporter Exporter) []string {
+ var warnings []string
+ if exporter.TLS != nil {
+ tls := exporter.TLS
+ if tls.Key != "" && tls.Cert == "" || tls.Cert != "" && tls.Key == "" {
+ warnings = append(warnings, "both exporter.tls.key and exporter.tls.cert mut be set")
+ }
+
+ if !strings.HasPrefix(exporter.Endpoint, "https://") {
+ warnings = append(warnings, "exporter.tls is configured but exporter.endpoint is not enabling TLS with https://")
+ }
+ }
+ if strings.HasPrefix(exporter.Endpoint, "https://") && exporter.TLS == nil {
+ warnings = append(warnings, "exporter is using https:// but exporter.tls is unset")
+ }
+
+ return warnings
+}
+
func validateJaegerRemoteSamplerArgument(argument string) error {
parts := strings.Split(argument, ",")
diff --git a/apis/v1alpha1/instrumentation_webhook_test.go b/apis/v1alpha1/instrumentation_webhook_test.go
index 81049cbc0c..9c6c1ae5c3 100644
--- a/apis/v1alpha1/instrumentation_webhook_test.go
+++ b/apis/v1alpha1/instrumentation_webhook_test.go
@@ -113,6 +113,94 @@ func TestInstrumentationValidatingWebhook(t *testing.T) {
},
},
},
+ {
+ name: "exporter: tls cert set but missing key",
+ inst: Instrumentation{
+ Spec: InstrumentationSpec{
+ Sampler: Sampler{
+ Type: ParentBasedTraceIDRatio,
+ Argument: "0.99",
+ },
+ Exporter: Exporter{
+ Endpoint: "https://collector:4317",
+ TLS: &TLS{
+ Cert: "cert",
+ },
+ },
+ },
+ },
+ warnings: []string{"both exporter.tls.key and exporter.tls.cert mut be set"},
+ },
+ {
+ name: "exporter: tls key set but missing cert",
+ inst: Instrumentation{
+ Spec: InstrumentationSpec{
+ Sampler: Sampler{
+ Type: ParentBasedTraceIDRatio,
+ Argument: "0.99",
+ },
+ Exporter: Exporter{
+ Endpoint: "https://collector:4317",
+ TLS: &TLS{
+ Key: "key",
+ },
+ },
+ },
+ },
+ warnings: []string{"both exporter.tls.key and exporter.tls.cert mut be set"},
+ },
+ {
+ name: "exporter: tls set but using http://",
+ inst: Instrumentation{
+ Spec: InstrumentationSpec{
+ Sampler: Sampler{
+ Type: ParentBasedTraceIDRatio,
+ Argument: "0.99",
+ },
+ Exporter: Exporter{
+ Endpoint: "http://collector:4317",
+ TLS: &TLS{
+ Key: "key",
+ Cert: "cert",
+ },
+ },
+ },
+ },
+ warnings: []string{"exporter.tls is configured but exporter.endpoint is not enabling TLS with https://"},
+ },
+ {
+ name: "exporter: exporter using http://, but the tls is nil",
+ inst: Instrumentation{
+ Spec: InstrumentationSpec{
+ Sampler: Sampler{
+ Type: ParentBasedTraceIDRatio,
+ Argument: "0.99",
+ },
+ Exporter: Exporter{
+ Endpoint: "https://collector:4317",
+ },
+ },
+ },
+ warnings: []string{"exporter is using https:// but exporter.tls is unset"},
+ },
+ {
+ name: "exporter no warning set",
+ inst: Instrumentation{
+ Spec: InstrumentationSpec{
+ Sampler: Sampler{
+ Type: ParentBasedTraceIDRatio,
+ Argument: "0.99",
+ },
+ Exporter: Exporter{
+ Endpoint: "https://collector:4317",
+ TLS: &TLS{
+ Key: "key",
+ Cert: "cert",
+ },
+ },
+ },
+ },
+ },
}
for _, test := range tests {
diff --git a/apis/v1alpha1/zz_generated.deepcopy.go b/apis/v1alpha1/zz_generated.deepcopy.go
index 270c617e17..5bf6ffaf0a 100644
--- a/apis/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/v1alpha1/zz_generated.deepcopy.go
@@ -171,6 +171,11 @@ func (in *DotNet) DeepCopy() *DotNet {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Exporter) DeepCopyInto(out *Exporter) {
*out = *in
+ if in.TLS != nil {
+ in, out := &in.TLS, &out.TLS
+ *out = new(TLS)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Exporter.
@@ -323,7 +328,7 @@ func (in *InstrumentationList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InstrumentationSpec) DeepCopyInto(out *InstrumentationSpec) {
*out = *in
- out.Exporter = in.Exporter
+ in.Exporter.DeepCopyInto(&out.Exporter)
in.Resource.DeepCopyInto(&out.Resource)
if in.Propagators != nil {
in, out := &in.Propagators, &out.Propagators
@@ -1272,6 +1277,21 @@ func (in *ScaleSubresourceStatus) DeepCopy() *ScaleSubresourceStatus {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TLS) DeepCopyInto(out *TLS) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLS.
+func (in *TLS) DeepCopy() *TLS {
+ if in == nil {
+ return nil
+ }
+ out := new(TLS)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TargetAllocator) DeepCopyInto(out *TargetAllocator) {
*out = *in
diff --git a/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml b/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml
index 0811d9a12b..e5b5bafdfc 100644
--- a/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml
+++ b/bundle/community/manifests/opentelemetry-operator.clusterserviceversion.yaml
@@ -99,7 +99,7 @@ metadata:
categories: Logging & Tracing,Monitoring
certified: "false"
containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator
- createdAt: "2024-10-08T09:52:53Z"
+ createdAt: "2024-10-10T15:31:51Z"
description: Provides the OpenTelemetry components, including the Collector
operators.operatorframework.io/builder: operator-sdk-v1.29.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
@@ -284,7 +284,9 @@ spec:
- ""
resources:
- namespaces
+ - secrets
verbs:
+ - get
- list
- watch
- apiGroups:
diff --git a/bundle/community/manifests/opentelemetry.io_instrumentations.yaml b/bundle/community/manifests/opentelemetry.io_instrumentations.yaml
index 76f050bf0d..4ff96eca41 100644
--- a/bundle/community/manifests/opentelemetry.io_instrumentations.yaml
+++ b/bundle/community/manifests/opentelemetry.io_instrumentations.yaml
@@ -409,6 +409,19 @@ spec:
properties:
endpoint:
type: string
+ tls:
+ properties:
+ ca:
+ type: string
+ cert:
+ type: string
+ configMapName:
+ type: string
+ key:
+ type: string
+ secretName:
+ type: string
+ type: object
type: object
go:
properties:
diff --git a/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml b/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml
index 24958408c7..bcab54329b 100644
--- a/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml
+++ b/bundle/openshift/manifests/opentelemetry-operator.clusterserviceversion.yaml
@@ -99,7 +99,7 @@ metadata:
categories: Logging & Tracing,Monitoring
certified: "false"
containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator
- createdAt: "2024-10-08T09:52:57Z"
+ createdAt: "2024-10-10T15:31:51Z"
description: Provides the OpenTelemetry components, including the Collector
operators.operatorframework.io/builder: operator-sdk-v1.29.0
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
@@ -284,7 +284,9 @@ spec:
- ""
resources:
- namespaces
+ - secrets
verbs:
+ - get
- list
- watch
- apiGroups:
diff --git a/bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml b/bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml
index 76f050bf0d..4ff96eca41 100644
--- a/bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml
+++ b/bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml
@@ -409,6 +409,19 @@ spec:
properties:
endpoint:
type: string
+ tls:
+ properties:
+ ca:
+ type: string
+ cert:
+ type: string
+ configMapName:
+ type: string
+ key:
+ type: string
+ secretName:
+ type: string
+ type: object
type: object
go:
properties:
diff --git a/config/crd/bases/opentelemetry.io_instrumentations.yaml b/config/crd/bases/opentelemetry.io_instrumentations.yaml
index 19582f62c6..3065e245a1 100644
--- a/config/crd/bases/opentelemetry.io_instrumentations.yaml
+++ b/config/crd/bases/opentelemetry.io_instrumentations.yaml
@@ -407,6 +407,19 @@ spec:
properties:
endpoint:
type: string
+ tls:
+ properties:
+ ca:
+ type: string
+ cert:
+ type: string
+ configMapName:
+ type: string
+ key:
+ type: string
+ secretName:
+ type: string
+ type: object
type: object
go:
properties:
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
index 73632f89c8..0991eb4d38 100644
--- a/config/rbac/role.yaml
+++ b/config/rbac/role.yaml
@@ -30,7 +30,9 @@ rules:
- ""
resources:
- namespaces
+ - secrets
verbs:
+ - get
- list
- watch
- apiGroups:
diff --git a/docs/api.md b/docs/api.md
index 24d16da3f4..71b3b7071a 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -1625,7 +1625,80 @@ Exporter defines exporter configuration.
endpoint |
string |
- Endpoint is address of the collector with OTLP endpoint.
+ Endpoint is address of the collector with OTLP endpoint.
+If the endpoint defines https:// scheme TLS has to be specified.
+ |
+ false |
+
+ tls |
+ object |
+
+ TLS defines certificates for TLS.
+TLS needs to be enabled by specifying https:// scheme in the Endpoint.
+ |
+ false |
+
+
+
+
+### Instrumentation.spec.exporter.tls
+[↩ Parent](#instrumentationspecexporter)
+
+
+
+TLS defines certificates for TLS.
+TLS needs to be enabled by specifying https:// scheme in the Endpoint.
+
+
+
+
+ Name |
+ Type |
+ Description |
+ Required |
+
+
+
+ ca |
+ string |
+
+ CA defines the key of certificate (e.g. ca.crt) in the configmap map, secret or absolute path to a certificate.
+The absolute path can be used when certificate is already present on the workload filesystem e.g.
+/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt
+ |
+ false |
+
+ cert |
+ string |
+
+ Cert defines the key (e.g. tls.crt) of the client certificate in the secret or absolute path to a certificate.
+The absolute path can be used when certificate is already present on the workload filesystem.
+ |
+ false |
+
+ configMapName |
+ string |
+
+ ConfigMapName defines configmap name with CA certificate. If it is not defined CA certificate will be
+used from the secret defined in SecretName.
+ |
+ false |
+
+ key |
+ string |
+
+ Key defines a key (e.g. tls.key) of the private key in the secret or absolute path to a certificate.
+The absolute path can be used when certificate is already present on the workload filesystem.
+ |
+ false |
+
+ secretName |
+ string |
+
+ SecretName defines secret name that will be used to configure TLS on the exporter.
+It is user responsibility to create the secret in the namespace of the workload.
+The secret must contain client certificate (Cert) and private key (Key).
+The CA certificate might be defined in the secret or in the config map.
|
false |
diff --git a/internal/webhook/podmutation/webhookhandler.go b/internal/webhook/podmutation/webhookhandler.go
index b4ad5fa7fc..a0704c5ad9 100644
--- a/internal/webhook/podmutation/webhookhandler.go
+++ b/internal/webhook/podmutation/webhookhandler.go
@@ -30,7 +30,7 @@ import (
)
// +kubebuilder:webhook:path=/mutate-v1-pod,mutating=true,failurePolicy=ignore,groups="",resources=pods,verbs=create,versions=v1,name=mpod.kb.io,sideEffects=none,admissionReviewVersions=v1
-// +kubebuilder:rbac:groups="",resources=namespaces,verbs=list;watch
+// +kubebuilder:rbac:groups="",resources=namespaces;secrets,verbs=get;list;watch
// +kubebuilder:rbac:groups=opentelemetry.io,resources=opentelemetrycollectors,verbs=get;list;watch
// +kubebuilder:rbac:groups=opentelemetry.io,resources=instrumentations,verbs=get;list;watch
// +kubebuilder:rbac:groups="apps",resources=replicasets,verbs=get;list;watch
diff --git a/pkg/constants/env.go b/pkg/constants/env.go
index 8dd4f65200..8bfcd667f4 100644
--- a/pkg/constants/env.go
+++ b/pkg/constants/env.go
@@ -15,12 +15,16 @@
package constants
const (
- EnvOTELServiceName = "OTEL_SERVICE_NAME"
- EnvOTELExporterOTLPEndpoint = "OTEL_EXPORTER_OTLP_ENDPOINT"
- EnvOTELResourceAttrs = "OTEL_RESOURCE_ATTRIBUTES"
- EnvOTELPropagators = "OTEL_PROPAGATORS"
- EnvOTELTracesSampler = "OTEL_TRACES_SAMPLER"
- EnvOTELTracesSamplerArg = "OTEL_TRACES_SAMPLER_ARG"
+ EnvOTELServiceName = "OTEL_SERVICE_NAME"
+ EnvOTELResourceAttrs = "OTEL_RESOURCE_ATTRIBUTES"
+ EnvOTELPropagators = "OTEL_PROPAGATORS"
+ EnvOTELTracesSampler = "OTEL_TRACES_SAMPLER"
+ EnvOTELTracesSamplerArg = "OTEL_TRACES_SAMPLER_ARG"
+
+ EnvOTELExporterOTLPEndpoint = "OTEL_EXPORTER_OTLP_ENDPOINT"
+ EnvOTELExporterCertificate = "OTEL_EXPORTER_OTLP_CERTIFICATE"
+ EnvOTELExporterClientCertificate = "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE"
+ EnvOTELExporterClientKey = "OTEL_EXPORTER_OTLP_CLIENT_KEY"
InstrumentationPrefix = "instrumentation.opentelemetry.io/"
AnnotationDefaultAutoInstrumentationJava = InstrumentationPrefix + "default-auto-instrumentation-java-image"
diff --git a/pkg/instrumentation/exporter.go b/pkg/instrumentation/exporter.go
new file mode 100644
index 0000000000..5598de24cf
--- /dev/null
+++ b/pkg/instrumentation/exporter.go
@@ -0,0 +1,150 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package instrumentation
+
+import (
+ "fmt"
+ "path/filepath"
+
+ corev1 "k8s.io/api/core/v1"
+
+ "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
+ "github.com/open-telemetry/opentelemetry-operator/internal/naming"
+ "github.com/open-telemetry/opentelemetry-operator/pkg/constants"
+)
+
+func configureExporter(exporter v1alpha1.Exporter, pod *corev1.Pod, container *corev1.Container) {
+ if exporter.Endpoint != "" {
+ if getIndexOfEnv(container.Env, constants.EnvOTELExporterOTLPEndpoint) == -1 {
+ container.Env = append(container.Env, corev1.EnvVar{
+ Name: constants.EnvOTELExporterOTLPEndpoint,
+ Value: exporter.Endpoint,
+ })
+ }
+ }
+ if exporter.TLS == nil {
+ return
+ }
+ // the name cannot be longer than 63 characters
+ secretVolumeName := naming.Truncate("otel-auto-secret-%s", 63, exporter.TLS.SecretName)
+ secretMountPath := fmt.Sprintf("/otel-auto-instrumentation-secret-%s", exporter.TLS.SecretName)
+ configMapVolumeName := naming.Truncate("otel-auto-configmap-%s", 63, exporter.TLS.ConfigMapName)
+ configMapMountPath := fmt.Sprintf("/otel-auto-instrumentation-configmap-%s", exporter.TLS.ConfigMapName)
+
+ if exporter.TLS.CA != "" {
+ mountPath := secretMountPath
+ if exporter.TLS.ConfigMapName != "" {
+ mountPath = configMapMountPath
+ }
+ envVarVal := fmt.Sprintf("%s/%s", mountPath, exporter.TLS.CA)
+ if filepath.IsAbs(exporter.TLS.CA) {
+ envVarVal = exporter.TLS.CA
+ }
+ if getIndexOfEnv(container.Env, constants.EnvOTELExporterCertificate) == -1 {
+ container.Env = append(container.Env, corev1.EnvVar{
+ Name: constants.EnvOTELExporterCertificate,
+ Value: envVarVal,
+ })
+ }
+ }
+ if exporter.TLS.Cert != "" {
+ envVarVal := fmt.Sprintf("%s/%s", secretMountPath, exporter.TLS.Cert)
+ if filepath.IsAbs(exporter.TLS.Cert) {
+ envVarVal = exporter.TLS.Cert
+ }
+ if getIndexOfEnv(container.Env, constants.EnvOTELExporterClientCertificate) == -1 {
+ container.Env = append(container.Env, corev1.EnvVar{
+ Name: constants.EnvOTELExporterClientCertificate,
+ Value: envVarVal,
+ })
+ }
+ }
+ if exporter.TLS.Key != "" {
+ envVarVar := fmt.Sprintf("%s/%s", secretMountPath, exporter.TLS.Key)
+ if filepath.IsAbs(exporter.TLS.Key) {
+ envVarVar = exporter.TLS.Key
+ }
+ if getIndexOfEnv(container.Env, constants.EnvOTELExporterClientKey) == -1 {
+ container.Env = append(container.Env, corev1.EnvVar{
+ Name: constants.EnvOTELExporterClientKey,
+ Value: envVarVar,
+ })
+ }
+ }
+
+ if exporter.TLS.SecretName != "" {
+ addVolume := true
+ for _, vol := range pod.Spec.Volumes {
+ if vol.Name == secretVolumeName {
+ addVolume = false
+ }
+ }
+ if addVolume {
+ pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
+ Name: secretVolumeName,
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: exporter.TLS.SecretName,
+ },
+ }})
+ }
+ addVolumeMount := true
+ for _, vol := range container.VolumeMounts {
+ if vol.Name == secretVolumeName {
+ addVolumeMount = false
+ }
+ }
+ if addVolumeMount {
+ container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
+ Name: secretVolumeName,
+ MountPath: secretMountPath,
+ ReadOnly: true,
+ })
+ }
+ }
+
+ if exporter.TLS.ConfigMapName != "" {
+ addVolume := true
+ for _, vol := range pod.Spec.Volumes {
+ if vol.Name == configMapVolumeName {
+ addVolume = false
+ }
+ }
+ if addVolume {
+ pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
+ Name: configMapVolumeName,
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: exporter.TLS.ConfigMapName,
+ },
+ },
+ }})
+ }
+ addVolumeMount := true
+ for _, vol := range container.VolumeMounts {
+ if vol.Name == configMapVolumeName {
+ addVolumeMount = false
+ }
+ }
+ if addVolumeMount {
+ container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
+ Name: configMapVolumeName,
+ MountPath: configMapMountPath,
+ ReadOnly: true,
+ })
+ }
+ }
+}
diff --git a/pkg/instrumentation/exporter_test.go b/pkg/instrumentation/exporter_test.go
new file mode 100644
index 0000000000..2fddf1264a
--- /dev/null
+++ b/pkg/instrumentation/exporter_test.go
@@ -0,0 +1,209 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package instrumentation
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ corev1 "k8s.io/api/core/v1"
+
+ "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
+)
+
+func TestExporter(t *testing.T) {
+ tests := []struct {
+ name string
+ exporter v1alpha1.Exporter
+ expected corev1.Pod
+ }{
+ {
+ name: "ca, crt and key from secret",
+ exporter: v1alpha1.Exporter{
+ Endpoint: "https://collector:4318",
+ TLS: &v1alpha1.TLS{
+ SecretName: "my-certs",
+ CA: "ca.crt",
+ Cert: "cert.crt",
+ Key: "key.key",
+ },
+ },
+ expected: corev1.Pod{
+ Spec: corev1.PodSpec{
+ Volumes: []corev1.Volume{
+ {
+ Name: "otel-auto-secret-my-certs",
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: "my-certs",
+ },
+ },
+ },
+ },
+ Containers: []corev1.Container{
+ {
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: "otel-auto-secret-my-certs",
+ ReadOnly: true,
+ MountPath: "/otel-auto-instrumentation-secret-my-certs",
+ },
+ },
+ Env: []corev1.EnvVar{
+ {
+ Name: "OTEL_EXPORTER_OTLP_ENDPOINT",
+ Value: "https://collector:4318",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CERTIFICATE",
+ Value: "/otel-auto-instrumentation-secret-my-certs/ca.crt",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE",
+ Value: "/otel-auto-instrumentation-secret-my-certs/cert.crt",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CLIENT_KEY",
+ Value: "/otel-auto-instrumentation-secret-my-certs/key.key",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: "crt and key from secret and ca from configmap",
+ exporter: v1alpha1.Exporter{
+ Endpoint: "https://collector:4318",
+ TLS: &v1alpha1.TLS{
+ SecretName: "my-certs",
+ ConfigMapName: "ca-bundle",
+ CA: "ca.crt",
+ Cert: "cert.crt",
+ Key: "key.key",
+ },
+ },
+ expected: corev1.Pod{
+ Spec: corev1.PodSpec{
+ Volumes: []corev1.Volume{
+ {
+ Name: "otel-auto-secret-my-certs",
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: "my-certs",
+ },
+ },
+ },
+ {
+ Name: "otel-auto-configmap-ca-bundle",
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "ca-bundle",
+ },
+ },
+ },
+ },
+ },
+ Containers: []corev1.Container{
+ {
+ VolumeMounts: []corev1.VolumeMount{
+ {
+ Name: "otel-auto-secret-my-certs",
+ ReadOnly: true,
+ MountPath: "/otel-auto-instrumentation-secret-my-certs",
+ },
+ {
+ Name: "otel-auto-configmap-ca-bundle",
+ ReadOnly: true,
+ MountPath: "/otel-auto-instrumentation-configmap-ca-bundle",
+ },
+ },
+ Env: []corev1.EnvVar{
+ {
+ Name: "OTEL_EXPORTER_OTLP_ENDPOINT",
+ Value: "https://collector:4318",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CERTIFICATE",
+ Value: "/otel-auto-instrumentation-configmap-ca-bundle/ca.crt",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE",
+ Value: "/otel-auto-instrumentation-secret-my-certs/cert.crt",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CLIENT_KEY",
+ Value: "/otel-auto-instrumentation-secret-my-certs/key.key",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: "ca, crt key absolute paths",
+ exporter: v1alpha1.Exporter{
+ Endpoint: "https://collector:4318",
+ TLS: &v1alpha1.TLS{
+ CA: "/ca.crt",
+ Cert: "/cert.crt",
+ Key: "/key.key",
+ },
+ },
+ expected: corev1.Pod{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Env: []corev1.EnvVar{
+ {
+ Name: "OTEL_EXPORTER_OTLP_ENDPOINT",
+ Value: "https://collector:4318",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CERTIFICATE",
+ Value: "/ca.crt",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE",
+ Value: "/cert.crt",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CLIENT_KEY",
+ Value: "/key.key",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ pod := corev1.Pod{
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {},
+ },
+ },
+ }
+ configureExporter(test.exporter, &pod, &pod.Spec.Containers[0])
+ assert.Equal(t, test.expected, pod)
+ })
+ }
+}
diff --git a/pkg/instrumentation/podmutator.go b/pkg/instrumentation/podmutator.go
index b1a2356d04..3c3a2f8e52 100644
--- a/pkg/instrumentation/podmutator.go
+++ b/pkg/instrumentation/podmutator.go
@@ -22,6 +22,7 @@ import (
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
@@ -395,6 +396,11 @@ func (pm *instPodMutator) Mutate(ctx context.Context, ns corev1.Namespace, pod c
return pod, err
}
+ if err = pm.validateInstrumentations(ctx, insts, ns.Name); err != nil {
+ logger.Error(err, "failed to validate instrumentations")
+ return pod, err
+ }
+
// We retrieve the annotation for podname
if pm.config.EnableMultiInstrumentation() {
err = insts.setLanguageSpecificContainers(ns.ObjectMeta, pod.ObjectMeta)
@@ -460,3 +466,55 @@ func (pm *instPodMutator) selectInstrumentationInstanceFromNamespace(ctx context
return &otelInsts.Items[0], nil
}
}
+
+func (pm *instPodMutator) validateInstrumentations(ctx context.Context, inst languageInstrumentations, podNamespace string) error {
+ instrumentations := []struct {
+ instrumentation *v1alpha1.Instrumentation
+ }{
+ {inst.Java.Instrumentation},
+ {inst.Python.Instrumentation},
+ {inst.NodeJS.Instrumentation},
+ {inst.DotNet.Instrumentation},
+ {inst.Go.Instrumentation},
+ {inst.ApacheHttpd.Instrumentation},
+ {inst.Nginx.Instrumentation},
+ {inst.Sdk.Instrumentation},
+ }
+ var errs []error
+ for _, i := range instrumentations {
+ if i.instrumentation != nil {
+ if err := pm.validateInstrumentation(ctx, i.instrumentation, podNamespace); err != nil {
+ errs = append(errs, err)
+ }
+ }
+ }
+
+ if len(errs) > 0 {
+ return errors.Join(errs...)
+ }
+ return nil
+}
+
+func (pm *instPodMutator) validateInstrumentation(ctx context.Context, inst *v1alpha1.Instrumentation, podNamespace string) error {
+ // Check if secret and configmap exists
+ // If they don't exist pod cannot start
+ var errs []error
+ if inst.Spec.Exporter.TLS != nil {
+ if inst.Spec.Exporter.TLS.SecretName != "" {
+ nsn := types.NamespacedName{Name: inst.Spec.Exporter.TLS.SecretName, Namespace: podNamespace}
+ if err := pm.Client.Get(ctx, nsn, &corev1.Secret{}); apierrors.IsNotFound(err) {
+ errs = append(errs, fmt.Errorf("secret %s with certificates does not exists: %w", nsn.String(), err))
+ }
+ }
+ if inst.Spec.Exporter.TLS.ConfigMapName != "" {
+ nsn := types.NamespacedName{Name: inst.Spec.Exporter.TLS.ConfigMapName, Namespace: podNamespace}
+ if err := pm.Client.Get(ctx, nsn, &corev1.ConfigMap{}); apierrors.IsNotFound(err) {
+ errs = append(errs, fmt.Errorf("configmap %s with CA certificate does not exists: %w", nsn.String(), err))
+ }
+ }
+ }
+ if len(errs) > 0 {
+ return errors.Join(errs...)
+ }
+ return nil
+}
diff --git a/pkg/instrumentation/podmutator_test.go b/pkg/instrumentation/podmutator_test.go
index 2eddd045f3..400d44c22b 100644
--- a/pkg/instrumentation/podmutator_test.go
+++ b/pkg/instrumentation/podmutator_test.go
@@ -42,6 +42,8 @@ func TestMutatePod(t *testing.T) {
expected corev1.Pod
inst v1alpha1.Instrumentation
ns corev1.Namespace
+ secret *corev1.Secret
+ configMap *corev1.ConfigMap
setFeatureGates func(t *testing.T)
config config.Config
}{
@@ -52,6 +54,18 @@ func TestMutatePod(t *testing.T) {
Name: "javaagent",
},
},
+ secret: &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-certs",
+ Namespace: "javaagent",
+ },
+ },
+ configMap: &corev1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "my-ca-bundle",
+ Namespace: "javaagent",
+ },
+ },
inst: v1alpha1.Instrumentation{
ObjectMeta: metav1.ObjectMeta{
Name: "example-inst",
@@ -103,6 +117,13 @@ func TestMutatePod(t *testing.T) {
},
Exporter: v1alpha1.Exporter{
Endpoint: "http://collector:12345",
+ TLS: &v1alpha1.TLS{
+ SecretName: "my-certs",
+ ConfigMapName: "my-ca-bundle",
+ CA: "ca.crt",
+ Cert: "cert.crt",
+ Key: "key.key",
+ },
},
},
},
@@ -136,6 +157,24 @@ func TestMutatePod(t *testing.T) {
},
},
},
+ {
+ Name: "otel-auto-secret-my-certs",
+ VolumeSource: corev1.VolumeSource{
+ Secret: &corev1.SecretVolumeSource{
+ SecretName: "my-certs",
+ },
+ },
+ },
+ {
+ Name: "otel-auto-configmap-my-ca-bundle",
+ VolumeSource: corev1.VolumeSource{
+ ConfigMap: &corev1.ConfigMapVolumeSource{
+ LocalObjectReference: corev1.LocalObjectReference{
+ Name: "my-ca-bundle",
+ },
+ },
+ },
+ },
},
InitContainers: []corev1.Container{
{
@@ -212,6 +251,18 @@ func TestMutatePod(t *testing.T) {
Name: "OTEL_SERVICE_NAME",
Value: "app",
},
+ {
+ Name: "OTEL_EXPORTER_OTLP_CERTIFICATE",
+ Value: "/otel-auto-instrumentation-configmap-my-ca-bundle/ca.crt",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE",
+ Value: "/otel-auto-instrumentation-secret-my-certs/cert.crt",
+ },
+ {
+ Name: "OTEL_EXPORTER_OTLP_CLIENT_KEY",
+ Value: "/otel-auto-instrumentation-secret-my-certs/key.key",
+ },
{
Name: "OTEL_RESOURCE_ATTRIBUTES_POD_NAME",
ValueFrom: &corev1.EnvVarSource{
@@ -238,6 +289,16 @@ func TestMutatePod(t *testing.T) {
Name: javaVolumeName,
MountPath: javaInstrMountPath,
},
+ {
+ Name: "otel-auto-secret-my-certs",
+ ReadOnly: true,
+ MountPath: "/otel-auto-instrumentation-secret-my-certs",
+ },
+ {
+ Name: "otel-auto-configmap-my-ca-bundle",
+ ReadOnly: true,
+ MountPath: "/otel-auto-instrumentation-configmap-my-ca-bundle",
+ },
},
},
},
@@ -4785,6 +4846,49 @@ func TestMutatePod(t *testing.T) {
config.WithEnableNodeJSInstrumentation(false),
),
},
+ {
+ name: "secret and configmap does not exists",
+ ns: corev1.Namespace{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "error-missing-secrets",
+ },
+ },
+ inst: v1alpha1.Instrumentation{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "example-inst",
+ Namespace: "error-missing-secrets",
+ },
+ Spec: v1alpha1.InstrumentationSpec{
+ Exporter: v1alpha1.Exporter{
+ Endpoint: "http://collector:12345",
+ TLS: &v1alpha1.TLS{
+ SecretName: "my-certs",
+ ConfigMapName: "my-ca-bundle",
+ CA: "ca.crt",
+ Cert: "cert.crt",
+ Key: "key.key",
+ },
+ },
+ },
+ },
+ pod: corev1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Annotations: map[string]string{
+ annotationInjectJava: "true",
+ },
+ Namespace: "error-missing-secrets",
+ },
+ Spec: corev1.PodSpec{
+ Containers: []corev1.Container{
+ {
+ Name: "app",
+ },
+ },
+ },
+ },
+ config: config.New(),
+ err: "secret error-missing-secrets/my-certs with certificates does not exists: secrets \"my-certs\" not found\nconfigmap error-missing-secrets/my-ca-bundle with CA certificate does not exists: configmaps \"my-ca-bundle\" not found",
+ },
}
for _, test := range tests {
@@ -4801,6 +4905,21 @@ func TestMutatePod(t *testing.T) {
defer func() {
_ = k8sClient.Delete(context.Background(), &test.ns)
}()
+ if test.secret != nil {
+ err = k8sClient.Create(context.Background(), test.secret)
+ require.NoError(t, err)
+ defer func() {
+ _ = k8sClient.Delete(context.Background(), test.secret)
+ }()
+ }
+ if test.configMap != nil {
+ err = k8sClient.Create(context.Background(), test.configMap)
+ require.NoError(t, err)
+ defer func() {
+ _ = k8sClient.Delete(context.Background(), test.configMap)
+ }()
+ }
+
err = k8sClient.Create(context.Background(), &test.inst)
require.NoError(t, err)
diff --git a/pkg/instrumentation/sdk.go b/pkg/instrumentation/sdk.go
index a9f7d9bbfd..0033f70566 100644
--- a/pkg/instrumentation/sdk.go
+++ b/pkg/instrumentation/sdk.go
@@ -304,15 +304,7 @@ func (i *sdkInjector) injectCommonSDKConfig(ctx context.Context, otelinst v1alph
Value: chooseServiceName(pod, useLabelsForResourceAttributes, resourceMap, appIndex),
})
}
- if otelinst.Spec.Exporter.Endpoint != "" {
- idx = getIndexOfEnv(container.Env, constants.EnvOTELExporterOTLPEndpoint)
- if idx == -1 {
- container.Env = append(container.Env, corev1.EnvVar{
- Name: constants.EnvOTELExporterOTLPEndpoint,
- Value: otelinst.Spec.Endpoint,
- })
- }
- }
+ configureExporter(otelinst.Spec.Exporter, &pod, container)
// Always retrieve the pod name from the Downward API. Ensure that the OTEL_RESOURCE_ATTRIBUTES_POD_NAME env exists.
container.Env = append(container.Env, corev1.EnvVar{
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/.gitignore b/tests/e2e-instrumentation/instrumentation-java-tls/.gitignore
new file mode 100644
index 0000000000..b8987f0ba0
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/.gitignore
@@ -0,0 +1,2 @@
+*.crt
+*.key
\ No newline at end of file
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/00-install-collector.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/00-install-collector.yaml
new file mode 100644
index 0000000000..536c392481
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/00-install-collector.yaml
@@ -0,0 +1,43 @@
+apiVersion: opentelemetry.io/v1beta1
+kind: OpenTelemetryCollector
+metadata:
+ name: simplest
+spec:
+ volumeMounts:
+ - name: certs
+ mountPath: /certs
+ - name: certs-ca
+ mountPath: /certs-ca
+ volumes:
+ - name: certs
+ secret:
+ secretName: server-certs
+ - name: certs-ca
+ configMap:
+ name: ca
+ config:
+ receivers:
+ otlp:
+ protocols:
+ grpc:
+ endpoint: 0.0.0.0:4317
+ tls:
+ cert_file: /certs/tls.crt
+ key_file: /certs/tls.key
+ client_ca_file: /certs-ca/ca.crt
+ http:
+ endpoint: 0.0.0.0:4318
+ tls:
+ cert_file: /certs/tls.crt
+ key_file: /certs/tls.key
+ client_ca_file: /certs-ca/ca.crt
+ processors:
+
+ exporters:
+ debug: {}
+
+ service:
+ pipelines:
+ traces:
+ receivers: [otlp]
+ exporters: [debug]
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/00-install-instrumentation.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/00-install-instrumentation.yaml
new file mode 100644
index 0000000000..222a0584a8
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/00-install-instrumentation.yaml
@@ -0,0 +1,19 @@
+apiVersion: opentelemetry.io/v1alpha1
+kind: Instrumentation
+metadata:
+ name: java
+spec:
+ exporter:
+ endpoint: https://simplest-collector:4317
+ tls:
+ secretName: client-certs
+ configMapName: ca
+ ca: ca.crt
+ cert: tls.crt
+ key: tls.key
+ propagators:
+ - tracecontext
+ - baggage
+ sampler:
+ type: parentbased_traceidratio
+ argument: "1"
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/01-assert.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/01-assert.yaml
new file mode 100644
index 0000000000..7ddecadb47
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/01-assert.yaml
@@ -0,0 +1,70 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ annotations:
+ instrumentation.opentelemetry.io/inject-java: "true"
+ labels:
+ app: my-java
+spec:
+ containers:
+ - env:
+ - name: OTEL_NODE_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.hostIP
+ - name: OTEL_POD_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
+ - name: JAVA_TOOL_OPTIONS
+ value: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'
+ - name: OTEL_SERVICE_NAME
+ value: my-java
+ - name: OTEL_EXPORTER_OTLP_ENDPOINT
+ value: https://simplest-collector:4317
+ - name: OTEL_EXPORTER_OTLP_CERTIFICATE
+ value: /otel-auto-instrumentation-configmap-ca/ca.crt
+ - name: OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE
+ value: /otel-auto-instrumentation-secret-client-certs/tls.crt
+ - name: OTEL_EXPORTER_OTLP_CLIENT_KEY
+ value: /otel-auto-instrumentation-secret-client-certs/tls.key
+ - name: OTEL_RESOURCE_ATTRIBUTES_POD_NAME
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: metadata.name
+ - name: OTEL_RESOURCE_ATTRIBUTES_NODE_NAME
+ valueFrom:
+ fieldRef:
+ apiVersion: v1
+ fieldPath: spec.nodeName
+ - name: OTEL_PROPAGATORS
+ value: tracecontext,baggage
+ - name: OTEL_TRACES_SAMPLER
+ value: parentbased_traceidratio
+ - name: OTEL_TRACES_SAMPLER_ARG
+ value: "1"
+ - name: OTEL_RESOURCE_ATTRIBUTES
+ name: myapp
+ volumeMounts:
+ - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
+ readOnly: true
+ - mountPath: /otel-auto-instrumentation-java
+ name: opentelemetry-auto-instrumentation-java
+ - mountPath: /otel-auto-instrumentation-secret-client-certs
+ name: otel-auto-secret-client-certs
+ readOnly: true
+ - mountPath: /otel-auto-instrumentation-configmap-ca
+ name: otel-auto-configmap-ca
+ readOnly: true
+ initContainers:
+ - name: opentelemetry-auto-instrumentation-java
+status:
+ containerStatuses:
+ - name: myapp
+ ready: true
+ started: true
+ initContainerStatuses:
+ - name: opentelemetry-auto-instrumentation-java
+ ready: true
+ phase: Running
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/01-install-app.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/01-install-app.yaml
new file mode 100644
index 0000000000..0d16826e53
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/01-install-app.yaml
@@ -0,0 +1,27 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: my-java
+spec:
+ selector:
+ matchLabels:
+ app: my-java
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: my-java
+ annotations:
+ instrumentation.opentelemetry.io/inject-java: "true"
+ spec:
+ securityContext:
+ runAsUser: 1000
+ runAsGroup: 3000
+ fsGroup: 3000
+ containers:
+ - name: myapp
+ image: ghcr.io/open-telemetry/opentelemetry-operator/e2e-test-app-java:main
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop: ["ALL"]
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/ca.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/ca.yaml
new file mode 100644
index 0000000000..c078708fd6
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/ca.yaml
@@ -0,0 +1,30 @@
+apiVersion: v1
+data:
+ ca.crt: |
+ -----BEGIN CERTIFICATE-----
+ MIID3zCCAsegAwIBAgIUbgTamPDD9mF7SzjykOtjZ6eOJygwDQYJKoZIhvcNAQEL
+ BQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
+ DU1vdW50YWluIFZpZXcxGjAYBgNVBAoMEVlvdXIgT3JnYW5pemF0aW9uMRIwEAYD
+ VQQLDAlZb3VyIFVuaXQxEjAQBgNVBAMMCWxvY2FsaG9zdDAgFw0yNDEwMTAxMjQw
+ MTFaGA8yMDUxMDMxMzEyNDAxMVowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
+ bGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxGjAYBgNVBAoMEVlvdXIg
+ T3JnYW5pemF0aW9uMRIwEAYDVQQLDAlZb3VyIFVuaXQxEjAQBgNVBAMMCWxvY2Fs
+ aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMax8x9QrIB924Tn
+ J+GhOsvEU6DDTbntLS8rXy7ePeCrUgjh+E3ThzvdZFqqx8ffVmrDVd8SF9TabXWC
+ j4Bytyv1AxBN8+PviXjyDeF5qSYEzh9K9poJCnTPOXZcToEna0Q5Po41fFY/M5QL
+ 7YHBrlc4rJKd+CJmQ0bjUj1OjG0NBT2Xm0rU1o92+73CMb//ADd8XkqDunHMfILe
+ wyWDiTbXsgXuh62cdmQyAL98xH0ghSrGYM2KA/F9FvD51B2+CDs2YwET4IsRTAt+
+ 9nLJpjrN7o+lofnhGWy88wPwlzJZeMP3oyna2iVlemXXYZeYXv2uRN6DCLUaamXT
+ sy2sawECAwEAAaNTMFEwHQYDVR0OBBYEFI7foDRaBz788AJJcAo0wC422LDUMB8G
+ A1UdIwQYMBaAFI7foDRaBz788AJJcAo0wC422LDUMA8GA1UdEwEB/wQFMAMBAf8w
+ DQYJKoZIhvcNAQELBQADggEBAIyVPNo2vsiRoqeJjaDCUSJFzop4ykdQOsOUMeJT
+ UqiJvH87unmEm50QgGOwsSxYPZkaPosxjnIFs9lVXixIcETtqbb8DT2AU9muDJ4o
+ 2p8tYBD/4jTN0I6waEpsubMwz+U4llxyfCG0UK3/6kpFwi8/723i8LwzynwkMiki
+ gtAPGmo1QwMFW/2w24l/+Uo4dhrq3GpuV2qBwyYc04z88abvAzRy/wIdw0IC4DiO
+ nNNN1SsjAeN+wp1dm0ohDm4z5d60O9CiTtggizzONJ8tln9SkyN6fCvpArgp9xxD
+ vChKkZiGSJlRoql1k8nRvHBaPZ9e3L8MEw7LgrkPSgleaNI=
+ -----END CERTIFICATE-----
+kind: ConfigMap
+metadata:
+ creationTimestamp: null
+ name: ca
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/chainsaw-test.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/chainsaw-test.yaml
new file mode 100755
index 0000000000..f552743fa3
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/chainsaw-test.yaml
@@ -0,0 +1,46 @@
+# yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/test-chainsaw-v1alpha1.json
+apiVersion: chainsaw.kyverno.io/v1alpha1
+kind: Test
+metadata:
+ creationTimestamp: null
+ name: instrumentation-java-tls
+spec:
+ steps:
+ - name: step-00
+ try:
+ # In OpenShift, when a namespace is created, all necessary SCC annotations are automatically added. However, if a namespace is created using a resource file with only selected SCCs, the other auto-added SCCs are not included. Therefore, the UID-range and supplemental groups SCC annotations must be set after the namespace is created.
+ - command:
+ entrypoint: kubectl
+ args:
+ - annotate
+ - namespace
+ - ${NAMESPACE}
+ - openshift.io/sa.scc.uid-range=1000/1000
+ - --overwrite
+ - command:
+ entrypoint: kubectl
+ args:
+ - annotate
+ - namespace
+ - ${NAMESPACE}
+ - openshift.io/sa.scc.supplemental-groups=3000/3000
+ - --overwrite
+ - apply:
+ file: ca.yaml
+ - apply:
+ file: client-secret.yaml
+ - apply:
+ file: server-secret.yaml
+ - apply:
+ file: 00-install-collector.yaml
+ - apply:
+ file: 00-install-instrumentation.yaml
+ - name: step-01
+ try:
+ - apply:
+ file: 01-install-app.yaml
+ - assert:
+ file: 01-assert.yaml
+ catch:
+ - podLogs:
+ selector: app=my-java
\ No newline at end of file
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/client-secret.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/client-secret.yaml
new file mode 100644
index 0000000000..d038b02d89
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/client-secret.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+data:
+ tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQ2VENDQXRHZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREIrTVFzd0NRWURWUVFHRXdKVlV6RVQKTUJFR0ExVUVDQXdLUTJGc2FXWnZjbTVwWVRFV01CUUdBMVVFQnd3TlRXOTFiblJoYVc0Z1ZtbGxkekVhTUJnRwpBMVVFQ2d3UldXOTFjaUJQY21kaGJtbDZZWFJwYjI0eEVqQVFCZ05WQkFzTUNWbHZkWElnVlc1cGRERVNNQkFHCkExVUVBd3dKYkc5allXeG9iM04wTUNBWERUSTBNVEF4TURFeU5EQXhNVm9ZRHpJd05URXdNekV6TVRJME1ERXgKV2pDQm1qRUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZqQVVCZ05WQkFjTQpEVTF2ZFc1MFlXbHVJRlpwWlhjeEdqQVlCZ05WQkFvTUVWbHZkWElnVDNKbllXNXBlbUYwYVc5dU1SSXdFQVlEClZRUUxEQWxaYjNWeUlGVnVhWFF4R2pBWUJnTlZCQU1NRVhOMll5NWpiSFZ6ZEdWeUxteHZZMkZzTVJJd0VBWUQKVlFRRERBbHNiMk5oYkdodmMzUXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDeApNSzljZDgvb0tHL0FGaTZUS2tsYmNzdlNSS0dTQUkvU2NSNVJQU3FoVW5sQ1NITEhpdXU0TDhSS202RGhGekVaCngvVVppSlREU3BWTllKcHpzZ1B5YkxWU1NQL2k5SDVqWGc3NW5MbUNUNmtRYWV5NG5EUjBZMEp3ZkdaaDB0eWwKMnpMMUlZdnVCYkZQTjMwRVp0bE82WVN3eWtqYjMwcjl3eFhrS1lsMFlCcEJFbkpqYyt5SW44OW52amNtTHgvVApkd3JPTlNXc2QzdXJpdXJNMWFWQlFjd09tMG8rMG9aVFdJY2daa2hPM0cvV29uZHBnSVl2OWF6dWYrL2craWs1ClQwZXBQR3RJSUsrajNqN3lGb3lkMFVONmprb2hyclV1bUFZRmF5UkdkRjhxNzc5dXIxZ0hIcXozRkE0YVY3aEoKd2JWNTNLV0ZCb2hLZEtqQkdVcHBBZ01CQUFHalV6QlJNQjBHQTFVZERnUVdCQlFhK2NpYTZvaS9RenhtZm43RgpiQnhOWTF0bXpEQWZCZ05WSFNNRUdEQVdnQlNPMzZBMFdnYysvUEFDU1hBS05NQXVOdGl3MURBUEJnTlZIUk1CCkFmOEVCVEFEQVFIL01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ0xvYTFIWnd5aGRQMyt4cXZYUzN5Z0FlbDAKMTdXWEpuM0FocndsajRxUFpvR2NrT0FYY1RoYm9ZaExITnV1ZVpPRkpIWFd4dU5lZDR2Y2xONEVocFdrWVRZTApodUtDN1IvVFVXVnAxMnh1SzNsdTBMZ3ZacUQ5bW05bTlXUW02eVJ5dmZCT0JBc3BLYXdtd0ljS0NLa3RCUnRpClRBaWxxNy9zOVZKRnFtSWNWWEg5bGtIaWNBMUROUjhMc2JSUWJtMUZOSCt4eGd1bTd6cURJbGZlZzhFMkg3WVIKVnRpNXZmZmRUUHVqZHlGaWZJbHR0cmw0MThwVDNVWEJ3UWFGRkVJSHlFdjlDamI5RFRMWDMrTDdlaWVYdXNrcgpxUkZzVjFIa3Arc1IwMTVNckxpUU9uOThjYUlKcG4yN3JOaU9GeVU2b3R3eTR0WGtmd0RTNlJLMkV5T24KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
+ tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3hNSzljZDgvb0tHL0EKRmk2VEtrbGJjc3ZTUktHU0FJL1NjUjVSUFNxaFVubENTSExIaXV1NEw4UkttNkRoRnpFWngvVVppSlREU3BWTgpZSnB6c2dQeWJMVlNTUC9pOUg1alhnNzVuTG1DVDZrUWFleTRuRFIwWTBKd2ZHWmgwdHlsMnpMMUlZdnVCYkZQCk4zMEVadGxPNllTd3lramIzMHI5d3hYa0tZbDBZQnBCRW5KamMreUluODludmpjbUx4L1Rkd3JPTlNXc2QzdXIKaXVyTTFhVkJRY3dPbTBvKzBvWlRXSWNnWmtoTzNHL1dvbmRwZ0lZdjlhenVmKy9nK2lrNVQwZXBQR3RJSUsragozajd5Rm95ZDBVTjZqa29ocnJVdW1BWUZheVJHZEY4cTc3OXVyMWdISHF6M0ZBNGFWN2hKd2JWNTNLV0ZCb2hLCmRLakJHVXBwQWdNQkFBRUNnZ0VBQ2ozZzZQbnc2R3BMN3FEKzcxa3luOGlqeTRNcTNwNzRob2FzejFwM0tCZDEKdEZVdWlKRDQvUzYwOXh0YlFoOXp6UVJ2NEVVSUtqM3U5dEpydUY1cUF0TEhRVVZyRmFjaHEyU0YvanRtNy9JTgpvNG45THVlSDB2d09IS1V5eXNVNWVwUmxYb3kzbUpvTXpMZDRSYTlITU1hU2VhQ0dTUlUxUndrd3hGSjZwRGExCml2am1neXZJRkp5L3RWMGxQSStUWHpnRzdzdkI1Y01CZDFVNjJXN2VkNDBDQWF6bmg1R09FZHZ1YmFaYmZmSWsKZ2huZ0N0ak5EU0p1Rk5ma1ZXdWNnTmErejVFK2dFYjZBdHJBMEhtZEtVR1V2UkRrNUhiVGZJR09ka0hzcnF5UApSSlk0WndFcEFxMWZhY2FxcWVwMXZsVU5vSmNNTVJhc29VOTZGU0lzelFLQmdRRFpCRFBUa0lQeFFNYXF1c3lDCmw5UkpRVy9OZGpuaDl3enRwOUhYWXNTcUEyU3VQQWVPMGdpWWdBOC9MZUpPTFhYelc0dWp2blhLcENveUNiQ3oKc0IvUm9MeTkrWENiODIzdDlKSTJvczZpbFhGbUo4S21OTUlQdExHVG82T1RJNlNseUNJMUFHRzdtdkVhVWY2SQpmanJaL25pY0c0Tlo5TU5rNVg0M2J5UjUzUUtCZ1FEUkJRU3VNWlNyVFFTMGpWbFZQaGxWdHRhV29vbTE5cFRjCmpjYS9vRTZ0Z2RRb2dUalVEZDlDRmtJZ1VxYmNpYlo0ZitnUmhHNHF4VkxwMDBxR0JLWFdYOXlBQTBtMmpNa3MKZkFDbTdZbFNvTElLNkY2M0FuWk9Kck5ETWYyejd1WWthWDBQRk4rTXZsLzRiQTFYMTFEcFRSdG4vL2QyLzBuMwpTeW1LWnVJWC9RS0JnRkh5TjB1OU4wVmpLMkdPdGVqZVFpZ0RVSjlwOUVOeVVXeHdRVm11andxUHkzWExieU1zCkJsam5pbHBXRGkxdEZ5djB0bzczUFcxdWZneDFBa2RueXl3U0lSTXZYS2xXeTN6ZUxGUDdPRUhHWXBLcmt1SEYKN0QyWUFySDRTYTBtK1dZc1kxWldOWkZzMlh3UjJDWmNYQWF6QTRJWEZZdGpWR0VHRTVvRkd1WDFBb0dBTTVXWAplQjRJWU5aYktPd1JkZllqYm9IM0o2bnBicHp5VkJReFRxMlRmVUtqUjNQTXdKakQxcDJEcUZKOWw4UHM0b1ErCms4UXBKQ2thczFaUCtBOUJsa3lHTUptZklZeFJRY2RBcWZISmlEamNkOUN0UDJFK0xUOWowbHVPRDFBUVFFQkEKZXU1ZDFYQk9ZeExYb0N3bGJjNTN5d3ppMTkxZE5jaTQ4YzArVTBrQ2dZRUF5eXdIYkcxOUd4dlNxZXNON2JCQgp6Yy8zYm1qczJocjMvYUxoQWUzMDZUbEdRUkg3Y3lCYzFpR2ZONTF0UTVqV01ZRHg1UndBMmNhUEwwcnl6REhmCjg0SktJeW1pVDB2ckFYRFN2bEorK21BVG1BQnNLcGpSVnpKWTJlVHFqNGQ1NUgyOUdudTVPVUtpMDY1Y2c5WEUKbVIrQ1o5Y1FqN212MDNVbW45MjVJWjQ9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
+kind: Secret
+metadata:
+ creationTimestamp: null
+ name: client-certs
+type: kubernetes.io/tls
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/generate-certs.sh b/tests/e2e-instrumentation/instrumentation-java-tls/generate-certs.sh
new file mode 100755
index 0000000000..d4070b03c9
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/generate-certs.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+set -ex
+
+# CA key and cert
+openssl req -new -nodes -x509 -days 9650 -keyout ca.key -out ca.crt -subj "/C=US/ST=California/L=Mountain View/O=Your Organization/OU=Your Unit/CN=localhost"
+# Server, E.g. use NDS:*.default.svc.cluster.local for arbitrary collector name deployed in the default namespace
+openssl req -new -nodes -x509 -CA ca.crt -CAkey ca.key -days 9650 -set_serial 01 -keyout server.key -out server.crt -subj "/C=US/ST=California/L=Mountain View/O=Your Organization/OU=Your Unit/CN=svc.cluster.local/CN=localhost" -addext "subjectAltName = DNS:simplest-collector,DNS:localhost"
+# Client
+openssl req -new -nodes -x509 -CA ca.crt -CAkey ca.key -days 9650 -set_serial 01 -keyout client.key -out client.crt -subj "/C=US/ST=California/L=Mountain View/O=Your Organization/OU=Your Unit/CN=svc.cluster.local/CN=localhost"
+
+kubectl create configmap ca --from-file=ca.crt=ca.crt -o yaml --dry-run=client > ca.yaml
+kubectl create secret tls server-certs --cert=server.crt --key=server.key -o yaml --dry-run=client > server-secret.yaml
+kubectl create secret tls client-certs --cert=client.crt --key=client.key -o yaml --dry-run=client > client-secret.yaml
diff --git a/tests/e2e-instrumentation/instrumentation-java-tls/server-secret.yaml b/tests/e2e-instrumentation/instrumentation-java-tls/server-secret.yaml
new file mode 100644
index 0000000000..63afbd2286
--- /dev/null
+++ b/tests/e2e-instrumentation/instrumentation-java-tls/server-secret.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+data:
+ tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVPVENDQXlHZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREIrTVFzd0NRWURWUVFHRXdKVlV6RVQKTUJFR0ExVUVDQXdLUTJGc2FXWnZjbTVwWVRFV01CUUdBMVVFQnd3TlRXOTFiblJoYVc0Z1ZtbGxkekVhTUJnRwpBMVVFQ2d3UldXOTFjaUJQY21kaGJtbDZZWFJwYjI0eEVqQVFCZ05WQkFzTUNWbHZkWElnVlc1cGRERVNNQkFHCkExVUVBd3dKYkc5allXeG9iM04wTUNBWERUSTBNVEF4TURFeU5EQXhNVm9ZRHpJd05URXdNekV6TVRJME1ERXgKV2pDQm1qRUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZqQVVCZ05WQkFjTQpEVTF2ZFc1MFlXbHVJRlpwWlhjeEdqQVlCZ05WQkFvTUVWbHZkWElnVDNKbllXNXBlbUYwYVc5dU1SSXdFQVlEClZRUUxEQWxaYjNWeUlGVnVhWFF4R2pBWUJnTlZCQU1NRVhOMll5NWpiSFZ6ZEdWeUxteHZZMkZzTVJJd0VBWUQKVlFRRERBbHNiMk5oYkdodmMzUXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFDcgpGN0U5SmtScldZYmM1Wkh2VU5GM2NZNVFaL0FrWktiN1Exend3aGFhQmtqVldWUEJCeUFmakNzM3laU3RGN2RkClo1VUxKNzN1VmtSdEJuTFd5bUJqbTZMN2xHVms2c0VqSXdFQkFUUDVJSksxdjBONFliSExYM1RJMDZXdlNCM2gKbGpjRzZOY0d0djE3NGFnbU1xZ05Bc0lmYlhEcW0xWkZSQzhCa0IwK2Jhc1hLUzJJS3VuSlIweEl1eTlFL09IWgp4b3hLUFFyQjNMcFBJNDAzSThPR2h1alZiY2xvVzh3UEljaVFwOGdJNVU3UWRJWmwzVkszcTZFWkNTVVhiMGNMClEyNnQ3TDZiRmlWcmhrTm5DZGtOU1Fybm55V2p4cldTdmdLTVZWaUtOVU1XQ0pGRWk1MytlSllxZkkzRTBhYXAKNlNsQ3NUQlE2akJYd0Y5R01mRURBZ01CQUFHamdhSXdnWjh3SFFZRFZSME9CQllFRkhZMjV2bmRHZGdDSC9zUgpMREx3Wmc4Ry9reXpNQjhHQTFVZEl3UVlNQmFBRkk3Zm9EUmFCejc4OEFKSmNBbzB3QzQyMkxEVU1BOEdBMVVkCkV3RUIvd1FGTUFNQkFmOHdUQVlEVlIwUkJFVXdRNElTYzJsdGNHeGxjM1F0WTI5c2JHVmpkRzl5Z2lJcUxuUnkKWVdOcGJtY3RjM2x6ZEdWdExuTjJZeTVqYkhWemRHVnlMbXh2WTJGc2dnbHNiMk5oYkdodmMzUXdEUVlKS29aSQpodmNOQVFFTEJRQURnZ0VCQURVNWtCUnRHaTlYalh5TUZJWEdKYTZtNEJrSTFOK0ZqUUprbGVSbWFOaWljRzhwCngzcnNBLzVVZU8wR0pDOXIrMWpxYThtVjhtUzcrMVVNUWJwMTZFUlZOVDBHWnA1TXNFdERqUHBveWFtM1JOZ1YKT2QwMnhZUUNNK3NGMVdNWll3M05FMEszTkJRcncyY3hoKzg2U29GdDBMdDEyYlBmbkxGTzJSdmI3b09aaHB0aApLNjJxaUlOVXAveG85S3hEelVhT1R1SndsTFdmTWQzMS80NFNyZm1hVWpGMWhKRDJ2SHZGeHZhcVNvSmJNK3pkCm1lbGo4cFhkS1ZJaWFRQ3hQZ1E4bTRHUmhQWkFuTk1pVlhiVm9vR05pelFaeEt2UWVwWnpXRTRXNmNFZTJtTWoKYlYvNVBOc3l5Mk0wOWY0MjlvTGxtNEpjb3IyMWZFSGVNVG1PYytzPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
+ tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3JGN0U5SmtScldZYmMKNVpIdlVORjNjWTVRWi9Ba1pLYjdRMXp3d2hhYUJralZXVlBCQnlBZmpDczN5WlN0RjdkZFo1VUxKNzN1VmtSdApCbkxXeW1Cam02TDdsR1ZrNnNFakl3RUJBVFA1SUpLMXYwTjRZYkhMWDNUSTA2V3ZTQjNobGpjRzZOY0d0djE3CjRhZ21NcWdOQXNJZmJYRHFtMVpGUkM4QmtCMCtiYXNYS1MySUt1bkpSMHhJdXk5RS9PSFp4b3hLUFFyQjNMcFAKSTQwM0k4T0dodWpWYmNsb1c4d1BJY2lRcDhnSTVVN1FkSVpsM1ZLM3E2RVpDU1VYYjBjTFEyNnQ3TDZiRmlWcgpoa05uQ2RrTlNRcm5ueVdqeHJXU3ZnS01WVmlLTlVNV0NKRkVpNTMrZUpZcWZJM0UwYWFwNlNsQ3NUQlE2akJYCndGOUdNZkVEQWdNQkFBRUNnZ0VBQWZ0d3lhQk10SVFoZzVYQzIrZUxvVVhvc1QxejYvVlo1d1BodVNsMW1laXIKU1QwTUZxT1Z4YjdvQ21MUFVsSFdNQkRtTlB5WjFGVUJhMkticjNEUUJCSVV0QWxhWDVqaU9TdDlYeGxVb3NNegp5cGg2MkZxeXUrZTd0Z2UwWGZ0elRMc05hRVBPNEp4dFdOVWgxcVJYdG1yZ1grQzU0aDdWSjFGSkU2L1dJblJJClF1ajEydytCTXVoUUcyRVM0cHpQQ2RtUGgvTkdSV1Q1K0NuamJzMkdjS1EvNXZIaXNnZVAyWEU2ZWRmbldCcFAKN0xNYjFCUGdLU09FTXZ2eUI2R2lMU2xwYWpKTmRtUHpmQmZURllWT05RTk5RYWJhRVFoNG9Gd2s1SkJKTlB5dQo1bCt2UlRpTEtZdk45YzB6Q1ZLa2NuZ0VyaXc0cTVCT3pPa3l1bGlNQVFLQmdRRHNzNkw2UVppNTRTOUh2ckRLCmxSMms4WlRoR1NSZ25uQ1Q2ZHVBcG50VEJpMWs3RUdGWFlWWGtIcEtpZEV5NFNKUmc4bXlSeTNjd1J3S2UzNVgKQVU5aURrajNjN3JLa041RmNleURqTzhXRVptdzZsb213aUtaczk0Y3FHY2tEWnEzSFNROStiMmNjZXFvc3QzSApOWE9ZUHBZdUZKUDAraFFEVFErSytXZUZBd0tCZ1FDNUNxNmJrSEFmQlp3OG5LeG5od3drV21JOTFjV3Fya21VCm5vamRPUkRxV1I1aWZDS05uQi9La0R4RHhGMDNRTjF5alpqcGZFOXdZRm42Vys4ZitPZXNBSGhaODRyZmhUTUgKTTd0VXZoNnNzcSt4QjhkWkJIeTRMd0prQTBPSFBqV2ZtaU96WllwczloUW5WRzAyRDBkdWZlWUNOd0hYN2hTRgptckp6RnJJa0FRS0JnUUNsclZiMk05UGl4MnVBbkVqQ2czMHNacXYrb3NxRGxtTFdKV291c2xpLzFDTVI4UXdyCmZUcElBQ2lZNDc0NkRyc21zMGdLTVNnNHpESUVaRXdhT2lDR1VkbGcydkJ6dU5MYmFOSlRnZUlYWUZwaktxWFAKV3pNOHdsbEZWZHBic2VvSklheXNkSkh6WHdrUTY2R3dQZ21iRnJPbnJWK2lxU2c0NTBkcHp3aFdZUUtCZ0JKNQpWWXRrZFQwem96Q045OHh5T0MwYzlQZjFjc0dpbXVnQ2wrbDJQQkVaaXFZTWZLcWtycXZia0ppM2J4TUlIOVBDCi9VUTZTL2dOTm81L1JUVnM5VHcvNDhRZlEzc2pZai9TMDE0WGlScDIwSUdkSkRMbjlzZXdzYzFvWWdLTG5IRHQKdzZpeWQ0cC9XdTIrU1JUL200TVZnTFF4NTdZMko4aGE5SHYzQlJ3QkFvR0FVMkNXRkJUWk1HL0NCZDhiOG5VeQpHblltNnhIMHpkeWdzK3JWakl5aEhBRXBTODZCaTZGSGh6TkNYRDFjSCtJWjAvYzR0QmYwSjhsVVRvOXpCV1YrClBJNjJOaEVMOW45WjMydTJGNzRDS0VTUi9EdUhTNXBTT2M3eXgvU3BOMjBpUkpodFl5aHA2YU9HMXQwL2NzRHAKVFpvOHlEdzl5cmVTdU9VSUFmM3JraG89Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
+kind: Secret
+metadata:
+ creationTimestamp: null
+ name: server-certs
+type: kubernetes.io/tls