手当たり次第に書くんだ

飽きっぽいのは本能

MicroK8s MetalLB speaker が ‘socket: permission denied’ を吐いた日

1. 背景

自宅クラスタで運用している MicroK8s (v1.32.9) 環境において、
突然MetalLBによるL2 LoadBalancerのVIPが応答しなくなった。

症状としては以下の通り:

  • 同一セグメント内ホストから curl https://<VIP>No route to host
  • ip neigh show <VIP>FAILED
  • arping → 応答なし
  • ただし、k8sノードそのものへの疎通は正常。

2. 原因の初期推定

最初に疑ったのはNATやルーティング。
しかしtracerouteや他ノードへの疎通テストで異常は見られず、
問題は明らかに VIPに対するARP応答の欠落 にあると判明した。

そこでMetalLB speakerのログを確認したところ、決定的なメッセージが出ていた:

creating ARP responder for "enp1s0": listen packet socket: permission denied

3. 原因の本質

要点はこれ一つ:

MicroK8s 1.32 のアップデートにより、seccompのデフォルトが強化され、speakerがAF_PACKETソケットを開けなくなった。

MetalLBのL2モードでは、ARP/NDPパケットを送出するために
コンテナ内で raw socket (AF_PACKET) を開く必要がある。
これがseccompの RuntimeDefault プロファイルによってブロックされていた。

他のログ・設定からも以下を確認:

  • pod-security.kubernetes.io/enforce: privileged は設定済み(PSAは犯人でない)
  • AppArmor は active(DENIEDログはないがpolicyが影響)
  • MetalLB speaker: quay.io/metallb/speaker:v0.13.3(古い世代)

つまり、MetalLB 0.13.x は新しいseccomp設定に非対応だった


4. 対応策(復旧手順)

seccompAppArmor の制限を一時的に解除するパッチを適用:

kubectl -n metallb-system patch ds speaker --type='json' -p='[
 {"op":"add","path":"/spec/template/spec/securityContext","value":{"seccompProfile":{"type":"Unconfined"}}},
 {"op":"add","path":"/spec/template/metadata/annotations/container.apparmor.security.beta.kubernetes.io~1speaker","value":"unconfined"},
 {"op":"add","path":"/spec/template/spec/containers/0/securityContext/allowPrivilegeEscalation","value":true}
]'
kubectl -n metallb-system rollout restart ds speaker

再起動後のログ:

created ARP responder for interface "enp1s0"
service has IP, announcing 10.145.0.192

そしてARP応答が復活:

arping 10.145.0.192
64 bytes from 10.145.0.192: index=0 time=0.512 msec

5. 恒久対応

一時的な kubectl patch は再デプロイで消えるため、
DaemonSetマニフェストに恒久的に反映しておく。

Kubernetes 1.30以降ではAppArmor注釈が非推奨のため、
次の形式が望ましい:

securityContext:
  seccompProfile:
    type: Unconfined
  appArmorProfile:
    type: Unconfined

6. 今後の選択肢

  1. MetalLBを0.14以降に更新
    → seccomp周りの調整が進んでおり、この問題は解消済み。
  2. BGPモードへの移行
    → ARP/NDP依存を排除し、L2層での権限問題を根本的に回避できる。
  3. 自作seccompプロファイルで最小権限を許可
    AF_PACKET など必要最小限のみ許可するローカルプロファイルを作成し、
    speakerに localhostProfile として適用する。

7. 教訓

Kubernetes とコンテナランタイムは、
「セキュリティ強化による後方互換性の崩壊」を静かに引き起こす。

L2でのARP/NDP制御のような低レイヤ操作を行うコンポーネントは、
この変化に最も敏感である。

セキュリティが強化された瞬間、それまでの権限前提は壊れる。


8. まとめ

項目状態
問題MetalLB speaker が ARP応答を出さずVIPが死んだ
原因seccompのデフォルト強化(RuntimeDefault有効化)
対処seccomp / AppArmor を Unconfined に設定
バージョンmicrok8s v1.32.9, metallb v0.13.3
教訓セキュリティ強化は“静かな破壊”を伴う
MicroK8s MetalLB speaker が ‘socket: permission denied’ を吐いた日

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トップへ戻る