Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,17 @@ func updateMainContainer(podSpec *corev1.PodSpec, hcp *hyperv1.HostedControlPlan
fmt.Sprintf("--v=%d", kasVerbosityLevel),
)

// We have to exempt the pod and service CIDR, otherwise the proxy will get respected by the transport inside
// the the egress transport and that breaks the egress selection/konnektivity usage.
// We have to exempt the pod, service, and machine CIDRs, otherwise the proxy will get respected by the
// transport inside the egress transport and that breaks the egress selection/konnectivity usage.
// The machine network must be included because KAS connects to kubelets on node IPs
// (for oc logs/exec/attach) via konnectivity; without it the management cluster proxy
// intercepts these HTTPS connections causing TLS failures.
// Using a CIDR is not supported by Go's default ProxyFunc, but Kube uses a custom one by default that does support it:
// https://github.com/kubernetes/kubernetes/blob/ab13c85316015cf9f115e29923ba9740bd1564fd/staging/src/k8s.io/apimachinery/pkg/util/net/http.go#L112-L114
var additionalNoProxyCIDRS []string
additionalNoProxyCIDRS = append(additionalNoProxyCIDRS, netutil.ClusterCIDRs(hcp.Spec.Networking.ClusterNetwork)...)
additionalNoProxyCIDRS = append(additionalNoProxyCIDRS, netutil.ServiceCIDRs(hcp.Spec.Networking.ServiceNetwork)...)
additionalNoProxyCIDRS = append(additionalNoProxyCIDRS, netutil.MachineCIDRs(hcp.Spec.Networking.MachineNetwork)...)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
proxy.SetEnvVars(&c.Env, additionalNoProxyCIDRS...)

if hcp.Annotations[hyperv1.KubeAPIServerGOGCAnnotation] != "" {
Expand Down

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggestion: Add a dual-stack test case. MachineNetwork supports up to 2 entries. A test with both IPv4 and IPv6 CIDRs (e.g., 192.168.1.0/24 + fd00::/48) would validate the iteration works correctly for dual-stack clusters.

Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,90 @@ import (

. "github.com/onsi/gomega"

hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
"github.com/openshift/hypershift/api/util/ipnet"

corev1 "k8s.io/api/core/v1"
)

func TestUpdateMainContainerNoProxy(t *testing.T) {
testCases := []struct {
name string
clusterNetwork []hyperv1.ClusterNetworkEntry
serviceNetwork []hyperv1.ServiceNetworkEntry
machineNetwork []hyperv1.MachineNetworkEntry
expectedCIDRs []string
}{
{
name: "When proxy is configured with machineNetwork it should include cluster service machine and kube-apiserver in NO_PROXY",
clusterNetwork: []hyperv1.ClusterNetworkEntry{{CIDR: *ipnet.MustParseCIDR("10.128.0.0/14")}},
serviceNetwork: []hyperv1.ServiceNetworkEntry{{CIDR: *ipnet.MustParseCIDR("172.30.0.0/16")}},
machineNetwork: []hyperv1.MachineNetworkEntry{{CIDR: *ipnet.MustParseCIDR("192.168.1.0/24")}},
expectedCIDRs: []string{"10.128.0.0/14", "172.30.0.0/16", "192.168.1.0/24", "kube-apiserver"},
},
{
name: "When proxy is configured without machineNetwork it should include cluster and service in NO_PROXY",
clusterNetwork: []hyperv1.ClusterNetworkEntry{{CIDR: *ipnet.MustParseCIDR("10.128.0.0/14")}},
serviceNetwork: []hyperv1.ServiceNetworkEntry{{CIDR: *ipnet.MustParseCIDR("172.30.0.0/16")}},
expectedCIDRs: []string{"10.128.0.0/14", "172.30.0.0/16", "kube-apiserver"},
},
{
name: "When proxy is configured with dual-stack machineNetwork it should include both IPv4 and IPv6 CIDRs in NO_PROXY",
clusterNetwork: []hyperv1.ClusterNetworkEntry{{CIDR: *ipnet.MustParseCIDR("10.128.0.0/14")}},
serviceNetwork: []hyperv1.ServiceNetworkEntry{{CIDR: *ipnet.MustParseCIDR("172.30.0.0/16")}},
machineNetwork: []hyperv1.MachineNetworkEntry{
{CIDR: *ipnet.MustParseCIDR("192.168.1.0/24")},
{CIDR: *ipnet.MustParseCIDR("fd00::/48")},
},
expectedCIDRs: []string{"10.128.0.0/14", "172.30.0.0/16", "192.168.1.0/24", "fd00::/48", "kube-apiserver"},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Setenv("HTTP_PROXY", "http://proxy.example.com:3128")
t.Setenv("HTTPS_PROXY", "http://proxy.example.com:3128")
t.Setenv("NO_PROXY", "")

hcp := &hyperv1.HostedControlPlane{
Spec: hyperv1.HostedControlPlaneSpec{
Networking: hyperv1.ClusterNetworking{
ClusterNetwork: tc.clusterNetwork,
ServiceNetwork: tc.serviceNetwork,
MachineNetwork: tc.machineNetwork,
},
},
}

podSpec := &corev1.PodSpec{
Containers: []corev1.Container{
{
Name: ComponentName,
Ports: []corev1.ContainerPort{
{ContainerPort: 6443},
},
},
},
}

updateMainContainer(podSpec, hcp)

g := NewWithT(t)
var noProxyValue string
for _, env := range podSpec.Containers[0].Env {
if env.Name == "NO_PROXY" {
noProxyValue = env.Value
break
}
}
g.Expect(noProxyValue).ToNot(BeEmpty(), "NO_PROXY env var should be set when proxy is configured")
for _, cidr := range tc.expectedCIDRs {
g.Expect(noProxyValue).To(ContainSubstring(cidr), "NO_PROXY should contain %s", cidr)
}
})
}
}

func TestAddImagePrePullInitContainers(t *testing.T) {
testCases := []struct {
name string
Expand Down