← Back to DevBytes

MetalLB Load Balancer Security Hardening and Best Practices

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:

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:

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:

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:

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.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles