Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .chloggen/insecure_endpoints.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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: opampbridge

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "Add TLS configuration support to the OpAMP Bridge, including options to disable TLS or skip certificate verification."

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

# (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:
13 changes: 13 additions & 0 deletions apis/v1alpha1/opampbridge_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ type OpAMPBridgeSpec struct {
// OpAMP backend Server endpoint
// +required
Endpoint string `json:"endpoint"`
// TLS configuration for the connection to the OpAMP backend server.
// +optional
TLS *OpAMPBridgeTLSConfig `json:"tls,omitempty"`
// Headers is an optional map of headers to use when connecting to the OpAMP Server,
// typically used to set access tokens or other authorization headers.
// +optional
Expand Down Expand Up @@ -120,6 +123,16 @@ type AgentDescription struct {
NonIdentifyingAttributes map[string]string `json:"non_identifying_attributes"`
}

type OpAMPBridgeTLSConfig struct {
// Insecure indicates whether the endpoint should use TLS or not.
// When true, TLS is completely disabled.
// +optional
Insecure bool `json:"insecure,omitempty" yaml:"insecure,omitempty"`
// InsecureSkipVerify indicates to keep TLS but skip certificate validation.
// +optional
InsecureSkipVerify bool `json:"insecure_skip_verify,omitempty" yaml:"insecure_skip_verify,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
Expand Down
20 changes: 20 additions & 0 deletions apis/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,13 @@ spec:
type: object
serviceAccount:
type: string
tls:
properties:
insecure:
type: boolean
insecure_skip_verify:
type: boolean
type: object
tolerations:
items:
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,13 @@ spec:
type: object
serviceAccount:
type: string
tls:
properties:
insecure:
type: boolean
insecure_skip_verify:
type: boolean
type: object
tolerations:
items:
properties:
Expand Down
35 changes: 34 additions & 1 deletion cmd/operator-opamp-bridge/internal/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ package agent
import (
"bytes"
"context"
"crypto/tls"
"errors"
"fmt"
"net/url"
"strings"
"time"

Expand Down Expand Up @@ -256,8 +258,34 @@ func (agent *Agent) Start() error {
},
RemoteConfigStatus: agent.remoteConfigStatus,
PackagesStateProvider: nil,
Capabilities: agent.config.GetCapabilities(),
}

// Configure TLS based on explicit tls settings.
if agent.config.TLS != nil {
if agent.config.TLS.Insecure {
parsedURL, parseErr := url.Parse(settings.OpAMPServerURL)
if parseErr != nil {
return fmt.Errorf("invalid OpAMP server endpoint %q: %w", settings.OpAMPServerURL, parseErr)
}

if parsedURL.Scheme == "wss" || parsedURL.Scheme == "https" {
return fmt.Errorf(
"tls.insecure=true requires an insecure endpoint scheme (ws:// or http://), but got %q. "+
"Please update the endpoint to use the insecure scheme when tls.insecure is enabled",
settings.OpAMPServerURL,
)
}

agent.logger.Info("TLS is disabled for the OpAMP client connection (tls.insecure=true). This connection is not encrypted.")
} else if agent.config.TLS.InsecureSkipVerify {
// TLS enabled but skip certificate verification (standard behavior)
settings.TLSConfig = &tls.Config{
InsecureSkipVerify: true, //nolint:gosec // User explicitly opted in via tls.insecure_skip_verify.
}
agent.logger.Info("TLS is enabled for the OpAMP client connection but certificate verification is skipped (tls.insecure_skip_verify=true)")
}
}

err = agent.opampClient.SetAgentDescription(agent.agentDescription)
if err != nil {
return err
Expand All @@ -266,6 +294,11 @@ func (agent *Agent) Start() error {
if err != nil {
return err
}
capabilities := agent.config.GetCapabilities()
err = agent.opampClient.SetCapabilities(&capabilities)
if err != nil {
return err
}

agent.logger.V(3).Info("Starting OpAMP client...")

Expand Down
64 changes: 64 additions & 0 deletions cmd/operator-opamp-bridge/internal/agent/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1258,3 +1258,67 @@ func getMessageDataFromConfigFile(filemap map[string]string) (*types.MessageData
}
return toReturn, nil
}

func TestAgent_Start_TLSConfig(t *testing.T) {
tests := []struct {
name string
endpoint string
insecure bool
insecureSkipVerify bool
expectNil bool
expectSkip bool
expectURL string
}{
{
name: "Insecure (no TLS)",
endpoint: "ws://127.0.0.1:4320/v1/opamp",
insecure: true,
expectNil: true,
expectURL: "ws://127.0.0.1:4320/v1/opamp",
},
{
name: "Secure with Skip Verify",
endpoint: "wss://127.0.0.1:4320/v1/opamp",
insecure: false,
insecureSkipVerify: true,
expectNil: false,
expectSkip: true,
expectURL: "wss://127.0.0.1:4320/v1/opamp",
},
{
name: "Secure (verify enabled)",
endpoint: "wss://127.0.0.1:4320/v1/opamp",
insecure: false,
insecureSkipVerify: false,
expectNil: true,
expectURL: "wss://127.0.0.1:4320/v1/opamp",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockClient := &mockOpampClient{}
conf := config.NewConfig(logr.Discard())
conf.Endpoint = tt.endpoint
conf.TLS = &v1alpha1.OpAMPBridgeTLSConfig{
Insecure: tt.insecure,
InsecureSkipVerify: tt.insecureSkipVerify,
}
applier := getFakeApplier(t, conf)
mp := newMockProxy(nil, nil, nil)
agent := NewAgent(l, applier, conf, mockClient, mp)

err := agent.Start()
require.NoError(t, err)

if tt.expectNil {
assert.Nil(t, mockClient.settings.TLSConfig)
} else {
require.NotNil(t, mockClient.settings.TLSConfig)
assert.Equal(t, tt.expectSkip, mockClient.settings.TLSConfig.InsecureSkipVerify)
}
assert.Equal(t, tt.expectURL, mockClient.settings.OpAMPServerURL)
agent.Shutdown()
})
}
}
15 changes: 8 additions & 7 deletions cmd/operator-opamp-bridge/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,14 @@ type Config struct {
instanceId uuid.UUID `yaml:"-"`

// ComponentsAllowed is a list of allowed OpenTelemetry components for each pipeline type (receiver, processor, etc.)
ComponentsAllowed map[string][]string `yaml:"componentsAllowed,omitempty"`
Endpoint string `yaml:"endpoint"`
Headers Headers `yaml:"headers,omitempty"`
Capabilities map[Capability]bool `yaml:"capabilities"`
HeartbeatInterval time.Duration `yaml:"heartbeatInterval,omitempty"`
Name string `yaml:"name,omitempty"`
AgentDescription AgentDescription `yaml:"description,omitempty"`
ComponentsAllowed map[string][]string `yaml:"componentsAllowed,omitempty"`
Endpoint string `yaml:"endpoint"`
TLS *v1alpha1.OpAMPBridgeTLSConfig `yaml:"tls,omitempty"`
Headers Headers `yaml:"headers,omitempty"`
Capabilities map[Capability]bool `yaml:"capabilities"`
HeartbeatInterval time.Duration `yaml:"heartbeatInterval,omitempty"`
Name string `yaml:"name,omitempty"`
AgentDescription AgentDescription `yaml:"description,omitempty"`
}

// AgentDescription is copied from the OpAMP Extension in the collector.
Expand Down
7 changes: 7 additions & 0 deletions config/crd/bases/opentelemetry.io_opampbridges.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,13 @@ spec:
type: object
serviceAccount:
type: string
tls:
properties:
insecure:
type: boolean
insecure_skip_verify:
type: boolean
type: object
tolerations:
items:
properties:
Expand Down
42 changes: 42 additions & 0 deletions docs/api/opampbridges.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,13 @@ default.<br/>
the operator will not automatically create a ServiceAccount for the OpAMPBridge.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#opampbridgespectls">tls</a></b></td>
<td>object</td>
<td>
TLS configuration for the connection to the OpAMP backend server.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#opampbridgespectolerationsindex">tolerations</a></b></td>
<td>[]object</td>
Expand Down Expand Up @@ -3483,6 +3490,41 @@ PodSecurityContext, the value specified in SecurityContext takes precedence.<br/
</table>


### OpAMPBridge.spec.tls
<sup><sup>[↩ Parent](#opampbridgespec)</sup></sup>



TLS configuration for the connection to the OpAMP backend server.

<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>insecure</b></td>
<td>boolean</td>
<td>
Insecure indicates whether the endpoint should use TLS or not.
When true, TLS is completely disabled.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>insecure_skip_verify</b></td>
<td>boolean</td>
<td>
InsecureSkipVerify indicates to keep TLS but skip certificate validation.<br/>
</td>
<td>false</td>
</tr></tbody>
</table>


### OpAMPBridge.spec.tolerations[index]
<sup><sup>[↩ Parent](#opampbridgespec)</sup></sup>

Expand Down
4 changes: 4 additions & 0 deletions internal/manifests/opampbridge/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ func ConfigMap(params manifests.Params) (*corev1.ConfigMap, error) {
config["endpoint"] = params.OpAMPBridge.Spec.Endpoint
}

if params.OpAMPBridge.Spec.TLS != nil {
config["tls"] = params.OpAMPBridge.Spec.TLS
}

if len(params.OpAMPBridge.Spec.Headers) > 0 {
config["headers"] = params.OpAMPBridge.Spec.Headers
}
Expand Down
4 changes: 4 additions & 0 deletions internal/webhook/opampbridge_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ func (*OpAMPBridgeWebhook) validate(r *v1alpha1.OpAMPBridge) (admission.Warnings
return warnings, errors.New("the OpAMP server endpoint is not specified")
}

if r.Spec.TLS != nil && r.Spec.TLS.Insecure && r.Spec.TLS.InsecureSkipVerify {
return warnings, errors.New("tls.insecure and tls.insecure_skip_verify cannot both be true")
}

// validate OpAMPBridge capabilities
if len(r.Spec.Capabilities) == 0 {
return warnings, errors.New("the capabilities supported by OpAMP Bridge are not specified")
Expand Down
16 changes: 16 additions & 0 deletions internal/webhook/opampbridge_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,22 @@ func TestOpAMPBridgeValidatingWebhook(t *testing.T) {
},
expectedErr: "the capabilities supported by OpAMP Bridge are not specified",
},
{
name: "insecure and insecure skip verify both set",
opampBridge: v1alpha1.OpAMPBridge{
Spec: v1alpha1.OpAMPBridgeSpec{
Endpoint: "ws://opamp-server:4320/v1/opamp",
TLS: &v1alpha1.OpAMPBridgeTLSConfig{
Insecure: true,
InsecureSkipVerify: true,
},
Capabilities: map[v1alpha1.OpAMPBridgeCapability]bool{
v1alpha1.OpAMPBridgeCapabilityReportsStatus: true,
},
},
},
expectedErr: "tls.insecure and tls.insecure_skip_verify cannot both be true",
},
{
name: "replica count greater than 1 should return error",
opampBridge: v1alpha1.OpAMPBridge{
Expand Down
2 changes: 2 additions & 0 deletions tests/e2e-opampbridge/opampbridge/01-assert.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ data:
receivers:
- otlp
endpoint: ws://e2e-test-app-bridge-server:4320/v1/opamp
tls:
insecure: true
kind: ConfigMap
metadata:
name: test-opamp-bridge
Expand Down
4 changes: 3 additions & 1 deletion tests/e2e-opampbridge/opampbridge/01-install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,6 @@ spec:
- memory_limiter
receivers:
- otlp
endpoint: ws://e2e-test-app-bridge-server:4320/v1/opamp
endpoint: ws://e2e-test-app-bridge-server:4320/v1/opamp
tls:
insecure: true
Loading
Loading