diff --git a/operator/internal/manifests/networkpolicy.go b/operator/internal/manifests/networkpolicy.go index 20833212ba877..f502b1b03f97e 100644 --- a/operator/internal/manifests/networkpolicy.go +++ b/operator/internal/manifests/networkpolicy.go @@ -324,9 +324,33 @@ func buildLokiAllowGatewayIngress(opts Options) *networkingv1.NetworkPolicy { // buildLokiAllowBucketEgress NetworkPolicy to allow egress traffic from // components that need to access object storage to object storage func buildLokiAllowBucketEgress(opts Options) *networkingv1.NetworkPolicy { - objstorePort := int32(443) // Default HTTPS port - if port := getEndpointPort(opts.ObjectStorage); port != 0 { - objstorePort = port + objstorePort := []int32{int32(443)} // Default HTTPS port + switch { + case opts.Stack.Proxy != nil: + proxyPorts := make([]int32, 0, 2) + if opts.Stack.Proxy.HTTPProxy != "" { + if port := extractPort(opts.Stack.Proxy.HTTPProxy); port != 0 { + proxyPorts = append(proxyPorts, port) + } + } + if opts.Stack.Proxy.HTTPSProxy != "" { + if port := extractPort(opts.Stack.Proxy.HTTPSProxy); port != 0 { + proxyPorts = append(proxyPorts, port) + } + } + objstorePort = proxyPorts + default: + if port := getEndpointPort(opts.ObjectStorage); port != 0 { + objstorePort = []int32{port} + } + } + + networkPorts := make([]networkingv1.NetworkPolicyPort, 0, len(objstorePort)) + for _, port := range objstorePort { + networkPorts = append(networkPorts, networkingv1.NetworkPolicyPort{ + Protocol: ptr.To(corev1.ProtocolTCP), + Port: &intstr.IntOrString{Type: intstr.Int, IntVal: port}, + }) } return &networkingv1.NetworkPolicy{ @@ -356,13 +380,8 @@ func buildLokiAllowBucketEgress(opts Options) *networkingv1.NetworkPolicy { Egress: []networkingv1.NetworkPolicyEgressRule{ // Allow egress to object storage { - To: []networkingv1.NetworkPolicyPeer{}, - Ports: []networkingv1.NetworkPolicyPort{ - { - Protocol: ptr.To(corev1.ProtocolTCP), - Port: &intstr.IntOrString{Type: intstr.Int, IntVal: objstorePort}, - }, - }, + To: []networkingv1.NetworkPolicyPeer{}, + Ports: networkPorts, }, }, }, @@ -630,30 +649,6 @@ func buildLokiAllowQueryFrontend(opts Options) *networkingv1.NetworkPolicy { } func getEndpointPort(storageOpts storage.Options) int32 { - extractPort := func(endpoint string) int32 { - if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") { - if u, err := url.Parse(endpoint); err == nil && u.Port() != "" { - if port, err := strconv.Atoi(u.Port()); err == nil { - return int32(port) - } - } - return 0 - } - - if strings.Contains(endpoint, ":") { - if epParts := strings.Split(endpoint, ":"); len(epParts) >= 2 { - portStr := epParts[len(epParts)-1] // last position should be the port - if idx := strings.Index(portStr, "/"); idx != -1 { - portStr = portStr[:idx] // remove the path if present - } - if port, err := strconv.Atoi(portStr); err == nil { - return int32(port) - } - } - } - - return 0 - } // Many self-hosted object storage solutions use S3 API endpoints // so we have to check for a port if storageOpts.S3 != nil && storageOpts.S3.Endpoint != "" { @@ -672,3 +667,28 @@ func getEndpointPort(storageOpts storage.Options) int32 { return 0 } + +func extractPort(endpoint string) int32 { + if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") { + if u, err := url.Parse(endpoint); err == nil && u.Port() != "" { + if port, err := strconv.Atoi(u.Port()); err == nil { + return int32(port) + } + } + return 0 + } + + if strings.Contains(endpoint, ":") { + if epParts := strings.Split(endpoint, ":"); len(epParts) >= 2 { + portStr := epParts[len(epParts)-1] // last position should be the port + if idx := strings.Index(portStr, "/"); idx != -1 { + portStr = portStr[:idx] // remove the path if present + } + if port, err := strconv.Atoi(portStr); err == nil { + return int32(port) + } + } + } + + return 0 +} diff --git a/operator/internal/manifests/networkpolicy_test.go b/operator/internal/manifests/networkpolicy_test.go index 608b04ddcdd41..32b67b9b344a5 100644 --- a/operator/internal/manifests/networkpolicy_test.go +++ b/operator/internal/manifests/networkpolicy_test.go @@ -315,9 +315,9 @@ func TestBuildLokiAllowGatewayIngress(t *testing.T) { func TestBuildLokiAllowBucketEgress(t *testing.T) { tests := []struct { - name string - opts Options - expectedPort int32 + name string + opts Options + expectedPorts []int32 }{ { name: "AWS S3 endpoint without port (defaults to 443)", @@ -331,7 +331,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) { }, }, }, - expectedPort: 443, + expectedPorts: []int32{443}, }, { name: "MinIO k8s service endpoint with custom port", @@ -345,7 +345,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) { }, }, }, - expectedPort: 9000, + expectedPorts: []int32{9000}, }, { name: "MinIO simple hostname with port", @@ -359,7 +359,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) { }, }, }, - expectedPort: 8080, + expectedPorts: []int32{8080}, }, { name: "Swift endpoint with custom port", @@ -373,7 +373,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) { }, }, }, - expectedPort: 5000, + expectedPorts: []int32{5000}, }, { name: "AlibabaCloud endpoint with custom port", @@ -387,7 +387,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) { }, }, }, - expectedPort: 8080, + expectedPorts: []int32{8080}, }, { name: "AlibabaCloud endpoint without port (defaults to 443)", @@ -401,7 +401,27 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) { }, }, }, - expectedPort: 443, + expectedPorts: []int32{443}, + }, + { + name: "HTTPS proxy endpoint with custom port", + opts: Options{ + Name: "test", + Namespace: "test-ns", + ObjectStorage: storage.Options{ + SharedStore: lokiv1.ObjectStorageSecretS3, + S3: &storage.S3StorageConfig{ + Endpoint: "https://s3.amazonaws.com", + }, + }, + Stack: lokiv1.LokiStackSpec{ + Proxy: &lokiv1.ClusterProxy{ + HTTPProxy: "http://proxy.example.com:8080", + HTTPSProxy: "http://proxy.example.com:6443", + }, + }, + }, + expectedPorts: []int32{8080, 6443}, }, } @@ -427,9 +447,10 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) { require.Empty(t, egressRule.To, "Egress should allow to any destination") // Verify the port - require.Len(t, egressRule.Ports, 1, "Should have exactly one port") - actualPort := egressRule.Ports[0].Port.IntVal - require.Equal(t, tc.expectedPort, actualPort, "Port should match expected value") + require.Len(t, egressRule.Ports, len(tc.expectedPorts), "Should have exactly one port") + for i, port := range egressRule.Ports { + require.Equal(t, tc.expectedPorts[i], port.Port.IntVal, "Port should match expected value") + } }) } }