Introduction to MetalLB Load Balancer Security
MetalLB is a powerful, bare-metal load balancer implementation for Kubernetes that allows you to expose Services of type LoadBalancer in clusters that do not run on a supported cloud provider. While MetalLB simplifies external access to your applications, its very nature—intercepting ARP/NDP requests or establishing BGP peering with routers—introduces a critical attack surface that must be hardened. This tutorial covers the essential security measures you need to apply to a MetalLB deployment to prevent IP hijacking, denial-of-service attacks, and unauthorized traffic interception.
Why MetalLB Security Matters
In a default or poorly configured MetalLB setup, an attacker with access to the same L2 network could spoof ARP responses, steal traffic meant for your legitimate services, or disrupt connectivity. In BGP mode, an unprotected BGP session can be hijacked by a rogue peer, allowing an adversary to advertise malicious routes and redirect traffic globally within your network. Additionally, insufficient RBAC rules could let a compromised pod manipulate MetalLB’s configuration, altering the IP pool or stealing addresses.
Understanding MetalLB Architecture and Attack Surface
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →MetalLB operates in two modes: Layer 2 (ARP/NDP) and BGP. Each has distinct security considerations.
Layer 2 Mode (ARP/NDP)
In L2 mode, MetalLB elects a leader node that responds to ARP (IPv4) or Neighbor Discovery Protocol (IPv6) requests for the load-balanced IP address. All traffic for that IP arrives at the leader node, which then forwards it to the appropriate backend pod via kube-proxy. The attack surface here includes:
- ARP Spoofing: A malicious node on the same broadcast domain can reply to ARP requests with its own MAC, stealing traffic.
- ARP Cache Poisoning: Unsolicited ARP replies can corrupt router/switch ARP tables.
- Leader Isolation: By disrupting leader election (e.g., via etcd or memberlist), an attacker can cause service downtime.
BGP Mode
In BGP mode, MetalLB peers with routers using the BGP protocol to advertise service IPs. Each node running MetalLB establishes BGP sessions and announces the IPs of services assigned to it. The attack surface includes:
- BGP Hijacking: A rogue peer can advertise more specific or lower-metric routes, redirecting traffic.
- Session Tampering: Without authentication (MD5/TCP-AO), an attacker can inject BGP messages.
- Route Leaking: Misconfigured filters can cause service IPs to be advertised to unintended networks.
Core Security Hardening Techniques
We’ll now cover concrete steps to harden MetalLB against these threats, with practical code examples.
1. Network Segmentation and ARP/NDP Protection
The first line of defense is isolating the network where MetalLB operates. If possible, place the load balancer IP range in a dedicated VLAN or subnet with strict access control. At the switch level, enable ARP inspection and DAI (Dynamic ARP Inspection) to block unsolicited ARP replies and verify sender IP-MAC bindings. For Kubernetes-specific protection, you can apply Network Policies to restrict which pods can send/receive raw ARP packets. MetalLB pods need to send gratuitous ARP; you can restrict raw socket capabilities.
# Example: Restricting raw sockets in the MetalLB deployment
# Add securityContext to the MetalLB controller and speaker pods
securityContext:
capabilities:
drop:
- ALL
add:
- NET_RAW # Required for ARP/NDP, but only granted to speaker
To limit ARP spoofing from within the cluster, apply a NetworkPolicy that only allows the MetalLB speaker pods to send ARP requests on the relevant interface. This requires CNI support for raw socket filtering (Calico, Cilium). Below is a sample Calico GlobalNetworkPolicy to restrict ARP to only MetalLB speaker endpoints.
# Calico GlobalNetworkPolicy: arp-restriction
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
name: restrict-arp
spec:
selector: '!has(projectcalico.org/namespace) || namespace != "metallb-system"'
types:
- Egress
egress:
- action: Deny
protocol: ARP
destination:
nets: [0.0.0.0/0]
# Allow MetalLB speaker pods
namespaceSelector: ''
rules:
- action: Allow
protocol: ARP
source:
selector: 'app == "metallb" && component == "speaker"'
2. IP Address Pool Protection
MetalLB uses IPAddressPool resources to define the IPs that can be assigned. Protect these objects with strict RBAC so only authorized users and controllers can modify them. Use separate namespaces for pools if you need multi-tenancy. Consider using AddressPool validation webhooks to prevent overlapping or dangerous ranges.
# Example RBAC rule: only the 'loadbalancer-admin' group can manage IPAddressPools
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metallb-pool-admin
rules:
- apiGroups: ["metallb.io"]
resources: ["ipaddresspools", "addresspools"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metallb-pool-admin-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metallb-pool-admin
subjects:
- kind: Group
name: loadbalancer-admin
apiGroup: rbac.authorization.k8s.io
Additionally, enable admission controller validation to prevent IP pool overlaps. MetalLB provides a validating webhook; ensure it's installed and configured. In the metallb Helm chart, set validation.webhook.enabled=true.
3. BGP Security: Authentication and Prefix Filtering
If using BGP mode, always configure MD5 password (for IPv4) or TCP Authentication Option (TCP-AO) (for IPv6) on every peering session. This prevents rogue peers from injecting routes. Additionally, apply strict prefix filters on your routers to only accept the exact service IPs that MetalLB is allowed to advertise. On the MetalLB side, limit the IPs announced by using IPAddressPool selections and BGPAdvertisement configurations.
# BGP Peer with MD5 authentication in MetalLB CRD
apiVersion: metallb.io/v1beta1
kind: BGPPeer
metadata:
name: router-peer
namespace: metallb-system
spec:
myASN: 64512
peerASN: 64513
peerAddress: 10.0.0.1
password: "your-secret-md5-password"
sourceAddress: 10.0.0.2
nodeSelectors:
- matchLabels:
bgp-enabled: "true"
On your router side (example for FRRouting/Bird):
# FRRouting BGP configuration snippet
router bgp 64513
neighbor 10.0.0.2 password your-secret-md5-password
neighbor 10.0.0.2 route-map metalb-in in
!
route-map metalb-in permit 10
match ip address prefix-list metallb-services
!
ip prefix-list metallb-services seq 5 permit 192.168.1.0/24 le 32
MetalLB also allows you to specify aggregationLength and community strings for more granular route control. Use BGPAdvertisement to restrict which pools are announced to which peers.
4. Kubernetes RBAC and Pod Security
MetalLB components run with certain privileges. The speaker needs NET_RAW to craft ARP/NDP packets; the controller needs access to MetalLB CRDs. Minimize these capabilities and apply Pod Security Standards. Use the restricted Pod Security Admission level for MetalLB pods if possible, but you may need exceptions for the speaker. Alternatively, use a custom SecurityPolicy (e.g., via Kyverno or OPA) to enforce:
# Kyverno policy: ensure speaker drops all capabilities except NET_RAW
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-metallb-speaker-capabilities
spec:
validationFailureAction: Enforce
rules:
- name: check-speaker-capabilities
match:
any:
- resources:
kinds:
- Deployment
namespaces:
- metallb-system
names:
- metallb-speaker
validate:
message: "Speaker must only have NET_RAW capability"
pattern:
spec:
template:
spec:
containers:
- =(securityContext):
capabilities:
add: ["NET_RAW"]
drop: ["ALL"]
5. Monitoring and Anomaly Detection
Deploy monitoring to detect ARP anomalies (e.g., multiple MACs replying for the same IP) and unexpected BGP withdrawals/advertisements. Prometheus metrics from MetalLB can be scraped. Set up alerts for:
- Sudden changes in
metallb_speaker_arp_requests_received - BGP session flapping (
metallb_bgp_session_uptransitions) - Unauthorized IP pool modifications via audit logs
Use a SIEM or log-based alerting on Kubernetes audit logs for any changes to IPAddressPool or BGPPeer resources.
# Example Prometheus alert for BGP session down
alert: MetalLBBGPPeerDown
expr: metallb_bgp_session_up{peer=~".+"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "BGP session to {{ $labels.peer }} is down"
Best Practices for Production Deployment
Summarized checklist:
- Use a dedicated VLAN/subnet for the load balancer IP range, separate from node management traffic.
- Enable ARP inspection/DAI on physical switches or virtual switches (e.g., Open vSwitch).
- Apply Network Policies to restrict ARP traffic to only MetalLB speaker pods.
- Lock down IPAddressPools with RBAC and validating webhooks.
- Always use BGP MD5 passwords or TCP-AO; never leave BGP sessions open.
- Filter BGP prefixes on the router side to only accept service IPs.
- Run MetalLB with minimal capabilities (drop ALL, add NET_RAW for speaker only).
- Enable audit logging for MetalLB CRDs.
- Monitor ARP and BGP metrics with alerting.
- Regularly update MetalLB to the latest stable version for security patches.
Implementation Example: End-to-End Secure L2 Deployment
Below is a complete snippet for a secure MetalLB L2 configuration with strict ARP protection and RBAC.
# MetalLB L2 Configuration with security hardening
# metallb-secure.yaml
---
apiVersion: v1
kind: Namespace
metadata:
name: metallb-system
---
# IPAddressPool with restricted CIDR
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: public-pool
namespace: metallb-system
spec:
addresses:
- 192.168.10.100-192.168.10.200
autoAssign: true
---
# L2Advertisement linking the pool
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: public-l2-ad
namespace: metallb-system
spec:
ipAddressPools:
- public-pool
---
# RBAC for pool protection
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metallb:pool-reader
rules:
- apiGroups: ["metallb.io"]
resources: ["ipaddresspools"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metallb:pool-reader-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metallb:pool-reader
subjects:
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
---
# Speaker DaemonSet with restricted security context
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: metallb-speaker
namespace: metallb-system
spec:
selector:
matchLabels:
app: metallb-speaker
template:
metadata:
labels:
app: metallb-speaker
spec:
serviceAccountName: metallb-speaker
hostNetwork: true
containers:
- name: metallb-speaker
image: metallb/speaker:v0.14.5
securityContext:
capabilities:
drop:
- ALL
add:
- NET_RAW
readOnlyRootFilesystem: true
env:
- name: METALLB_ML_SECRET
valueFrom:
secretKeyRef:
name: memberlist
key: secretkey
---
# NetworkPolicy (Calico) to restrict ARP egress to only speaker pods
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: metallb-arp-restrict
namespace: metallb-system
spec:
selector: app == "metallb-speaker"
egress:
- action: Allow
protocol: ARP
- action: Deny
# Deny all other traffic if needed, but keep basic connectivity
Conclusion
Securing MetalLB requires a layered approach that spans network infrastructure, Kubernetes RBAC, pod hardening, and monitoring. By implementing ARP/NDP protection, BGP authentication, strict IP pool management, and minimal privilege enforcement, you can safely expose your services on bare-metal Kubernetes without opening the door to traffic hijacking or denial-of-service attacks. Regularly audit your configuration and keep MetalLB updated to benefit from the latest security improvements.