Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix webhook error when metrics service address uses env var expansion #3531

Merged
18 changes: 18 additions & 0 deletions .chloggen/fix-metrics-service-address-env-var.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: bug_fix

# 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: operator

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Fix the admission webhook to when metrics service address host uses env var expansion

# One or more tracking issues related to the change
issues: [3513]

# (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: |
This should allow the metrics service address to have the host portion expanded from an environment variable,
Copy link
Contributor

Choose a reason for hiding this comment

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

Please inform that you enabled the IPv6.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@yuriolisa I didn’t necessarily enable ipv6. I only refactored that ‘Service.MetricsEndpoint’ method in a way that it also works with ipv6 addresses. I do not know if the project has everything else that is needed for full ipv6 support. Do you know about this?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think there's a need to specifically call out IPv6. We only care about the port to begin with.

like `$(env:POD_IP)` instead of using `0.0.0.0`, which is the [recommended by the Collector](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/security-best-practices.md#safeguards-against-denial-of-service-attacks).
12 changes: 11 additions & 1 deletion apis/v1beta1/collector_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,17 @@ func TestOTELColValidatingWebhook(t *testing.T) {
five := int32(5)
maxInt := int32(math.MaxInt32)

cfg := v1beta1.Config{}
cfg := v1beta1.Config{
Service: v1beta1.Service{
Telemetry: &v1beta1.AnyConfig{
Object: map[string]interface{}{
"metrics": map[string]interface{}{
"address": "${env:POD_ID}:8888",
},
},
},
},
}
err := yaml.Unmarshal([]byte(cfgYaml), &cfg)
require.NoError(t, err)

Expand Down
26 changes: 24 additions & 2 deletions apis/v1beta1/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,16 +427,18 @@
Pipelines map[string]*Pipeline `json:"pipelines" yaml:"pipelines"`
}

const defaultServicePort int32 = 8888

// MetricsEndpoint gets the port number and host address for the metrics endpoint from the collector config if it has been set.
func (s *Service) MetricsEndpoint() (string, int32, error) {
defaultAddr := "0.0.0.0"
if s.GetTelemetry() == nil {
// telemetry isn't set, use the default
return defaultAddr, 8888, nil
return defaultAddr, defaultServicePort, nil
}
host, port, netErr := net.SplitHostPort(s.GetTelemetry().Metrics.Address)
if netErr != nil && strings.Contains(netErr.Error(), "missing port in address") {
return defaultAddr, 8888, nil
return defaultAddr, defaultServicePort, nil
} else if netErr != nil {
return "", 0, netErr
}
Expand All @@ -452,6 +454,26 @@
return host, int32(i64), nil
}

// NaivePort attempts gets the port number from the host address without doing any validation regarding the address itself.
// It works even before env var expansion happens, when a simple `net.SplitHostPort` would fail because of the extra colon
// from the env var, i.e. the address looks like "${env:POD_IP}:4317" or "${env:POD_IP}".
// It does not work in cases which the port itself is a variable, i.e. "${env:POD_IP}:${env:PORT}".
func (s *Service) NaivePort() (int32, error) {
telemetry := s.GetTelemetry()
if telemetry == nil {
return defaultServicePort, nil
}
splitAddress := strings.Split(telemetry.Metrics.Address, ":")
if len(splitAddress) == 1 {
return defaultServicePort, nil
}
port, err := strconv.Atoi(splitAddress[len(splitAddress)-1])
if err != nil {
return 0, err
}
return int32(port), nil

Check failure on line 474 in apis/v1beta1/config.go

View workflow job for this annotation

GitHub Actions / Code standards (linting)

G109: Potential Integer overflow made by strconv.Atoi result conversion to int16/32 (gosec)
}

// ApplyDefaults inserts configuration defaults if it has not been set.
func (s *Service) ApplyDefaults() error {
telemetryAddr, telemetryPort, err := s.MetricsEndpoint()
Expand Down
3 changes: 1 addition & 2 deletions internal/manifests/collector/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ func HeadlessService(params manifests.Params) (*corev1.Service, error) {
}

func MonitoringService(params manifests.Params) (*corev1.Service, error) {

name := naming.MonitoringService(params.OtelCol.Name)
labels := manifestutils.Labels(params.OtelCol.ObjectMeta, name, params.OtelCol.Spec.Image, ComponentOpenTelemetryCollector, []string{})
labels[monitoringLabel] = valueExists
Expand All @@ -84,7 +83,7 @@ func MonitoringService(params manifests.Params) (*corev1.Service, error) {
return nil, err
}

_, metricsPort, err := params.OtelCol.Spec.Config.Service.MetricsEndpoint()
metricsPort, err := params.OtelCol.Spec.Config.Service.NaivePort()
if err != nil {
return nil, err
}
Expand Down
Loading