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
28 changes: 28 additions & 0 deletions pkg/render/istio/istio.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,20 @@ func (c *IstioComponent) istiodCalicoSystemPolicy() *v3.NetworkPolicy {
},
}

// In BPF mode, CTLB is disabled for Istio ambient compatibility. Without CTLB and
// kube-proxy, return traffic (SYN-ACKs) from istiod to ztunnel on remote nodes may not
// be matched by conntrack. Allow explicit egress to ztunnel pods to ensure cross-node
// ztunnel<->istiod communication works.
if c.cfg.Installation.BPFEnabled() {
egressRules = append(egressRules, v3.Rule{
Action: v3.Allow,
Protocol: &networkpolicy.TCPProtocol,
Destination: v3.EntityRule{
Selector: networkpolicy.KubernetesAppSelector(IstioZTunnelDaemonSetName),
},
})
}

// * Port 15012, gRPC, XDS and CA services (TLS and mTLS)
// ztunnel and waypoints connect to it to request certs and dataplane
// info.
Expand Down Expand Up @@ -385,6 +399,20 @@ func (c *IstioComponent) ztunnelCalicoSystemPolicy() *v3.NetworkPolicy {
Destination: networkpolicy.CreateServiceSelectorEntityRule(c.cfg.IstioNamespace, IstioIstiodServiceName),
},
}

// In BPF mode, CTLB is disabled for Istio ambient compatibility. Service-based egress
// selectors don't resolve correctly for cross-node traffic without CTLB and kube-proxy.
// Add a direct pod-selector rule so ztunnel can reach istiod by pod IP on any node.
if c.cfg.Installation.BPFEnabled() {
egressRules = append(egressRules, v3.Rule{
Action: v3.Allow,
Protocol: &networkpolicy.TCPProtocol,
Destination: v3.EntityRule{
Selector: networkpolicy.KubernetesAppSelector(IstioIstiodDeploymentName),
},
})
}

egressRules = networkpolicy.AppendDNSEgressRules(egressRules, c.cfg.Installation.KubernetesProvider.IsOpenShift())

return &v3.NetworkPolicy{
Expand Down
52 changes: 52 additions & 0 deletions pkg/render/istio/istio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,58 @@ var _ = Describe("Istio Component Rendering", func() {
Expect(foundIstiodRule).To(BeTrue(), "Expected egress rule for istiod service")
})

It("should add pod-selector egress rules when BPF dataplane is enabled", func() {
bpfDataplane := operatorv1.LinuxDataplaneBPF
cfg.Installation.CalicoNetwork = &operatorv1.CalicoNetworkSpec{
LinuxDataplane: &bpfDataplane,
}
_, component, err := istio.Istio(cfg)
Expect(err).ShouldNot(HaveOccurred())
Expect(component.ResolveImages(getCalicoTestImageSet())).ShouldNot(HaveOccurred())
objsToCreate, _ := component.Objects()

// Verify istiod policy has egress rule to ztunnel pods
istiodPolicy, err := rtest.GetResourceOfType[*v3.NetworkPolicy](objsToCreate, istio.IstioIstiodPolicyName, istio.IstioNamespace)
Expect(err).ShouldNot(HaveOccurred())
Expect(istiodPolicy.Spec.Egress).To(HaveLen(2))
Expect(istiodPolicy.Spec.Egress[1].Destination.Selector).To(Equal(
networkpolicy.KubernetesAppSelector(istio.IstioZTunnelDaemonSetName),
))

// Verify ztunnel policy has pod-selector egress rule to istiod
ztunnelPolicy, err := rtest.GetResourceOfType[*v3.NetworkPolicy](objsToCreate, istio.IstioZTunnelPolicyName, istio.IstioNamespace)
Expect(err).ShouldNot(HaveOccurred())
foundPodSelectorRule := false
for _, rule := range ztunnelPolicy.Spec.Egress {
if rule.Destination.Selector == networkpolicy.KubernetesAppSelector(istio.IstioIstiodDeploymentName) {
foundPodSelectorRule = true
break
}
}
Expect(foundPodSelectorRule).To(BeTrue(), "Expected pod-selector egress rule for istiod when BPF enabled")
})

It("should not add pod-selector egress rules when BPF dataplane is not enabled", func() {
_, component, err := istio.Istio(cfg)
Expect(err).ShouldNot(HaveOccurred())
Expect(component.ResolveImages(getCalicoTestImageSet())).ShouldNot(HaveOccurred())
objsToCreate, _ := component.Objects()

// Verify istiod policy has only 1 egress rule (kube API server)
istiodPolicy, err := rtest.GetResourceOfType[*v3.NetworkPolicy](objsToCreate, istio.IstioIstiodPolicyName, istio.IstioNamespace)
Expect(err).ShouldNot(HaveOccurred())
Expect(istiodPolicy.Spec.Egress).To(HaveLen(1))

// Verify ztunnel policy has no pod-selector rule for istiod
ztunnelPolicy, err := rtest.GetResourceOfType[*v3.NetworkPolicy](objsToCreate, istio.IstioZTunnelPolicyName, istio.IstioNamespace)
Expect(err).ShouldNot(HaveOccurred())
for _, rule := range ztunnelPolicy.Spec.Egress {
Expect(rule.Destination.Selector).NotTo(Equal(
networkpolicy.KubernetesAppSelector(istio.IstioIstiodDeploymentName),
), "Should not have pod-selector egress rule for istiod when BPF is not enabled")
}
})

It("should set TRANSPARENT_NETWORK_POLICIES env var on ztunnel", func() {
_, component, err := istio.Istio(cfg)
Expect(err).ShouldNot(HaveOccurred())
Expand Down
Loading