Skip to content
Open
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
88 changes: 54 additions & 34 deletions operator/internal/manifests/networkpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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,
},
},
},
Expand Down Expand Up @@ -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 != "" {
Expand All @@ -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
}
45 changes: 33 additions & 12 deletions operator/internal/manifests/networkpolicy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand All @@ -331,7 +331,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) {
},
},
},
expectedPort: 443,
expectedPorts: []int32{443},
},
{
name: "MinIO k8s service endpoint with custom port",
Expand All @@ -345,7 +345,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) {
},
},
},
expectedPort: 9000,
expectedPorts: []int32{9000},
},
{
name: "MinIO simple hostname with port",
Expand All @@ -359,7 +359,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) {
},
},
},
expectedPort: 8080,
expectedPorts: []int32{8080},
},
{
name: "Swift endpoint with custom port",
Expand All @@ -373,7 +373,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) {
},
},
},
expectedPort: 5000,
expectedPorts: []int32{5000},
},
{
name: "AlibabaCloud endpoint with custom port",
Expand All @@ -387,7 +387,7 @@ func TestBuildLokiAllowBucketEgress(t *testing.T) {
},
},
},
expectedPort: 8080,
expectedPorts: []int32{8080},
},
{
name: "AlibabaCloud endpoint without port (defaults to 443)",
Expand All @@ -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},
},
}

Expand All @@ -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")
}
})
}
}
Expand Down
Loading