Ingress arrives on the host network, not a LoadBalancer¶
There is no LoadBalancer, no VIP and no LB-IPAM pool. Cilium's Gateway API runs in
host network mode (gatewayAPI.hostNetwork.enabled), which exposes the
per-node Envoy listener directly on every node, and the router dst-nats :8443 to
a node's :443. Nothing is announced, so there is no BGP and no static route to
an address the cluster owns.
On the MikroTik side, To Ports must be set to 443. Leave it empty and
dst-nat preserves the original port, forwarding to :8443 where nothing is
listening — the connection is refused in milliseconds, which looks exactly like
a firewall block but is not one.
In host network mode the Gateway listener port is the host port. There is
no mapping, so spec.listeners[].port is 443 rather than some higher number the
chart then republishes. Envoy holds no Linux capabilities by default and cannot
bind below 1024, so that costs two Helm values:
envoy = {
enabled = true
securityContext = {
capabilities = {
keepCapNetBindService = true
envoy = ["NET_ADMIN", "SYS_ADMIN", "NET_BIND_SERVICE"]
}
}
}
keepCapNetBindService is what survives cilium-envoy-starter dropping
capabilities around the Envoy process; granting the capability to the container
alone is not enough. These live under envoy.* because the standalone
cilium-envoy DaemonSet is what runs — in embedded mode the capability goes on
securityContext.capabilities.ciliumAgent instead.
What host network mode does not cost is a Pod Security exemption. Envoy runs
in kube-system, which Talos leaves unenforced, so no namespace needs a
pod-security.kubernetes.io/enforce: privileged label for ingress — unlike the
hostPort workloads described in the resolver.
Two restrictions come with it, neither of which applies here: host network mode
and the LoadBalancer Service mode are mutually exclusive, and TCPRoute/
UDPRoute traffic bypasses Envoy and would land on a NodePort with a random
port instead of the listener's.
Envoy owns :443 on every node exclusively. A second process binding it — a
hostPort DaemonSet, or a second Envoy during a rollout — fails with
EADDRINUSE, and the Gateway stays un-Programmed until the port is free.