Skip to content

feat(talos): ノードの受信の防火壁 (Ingress Firewall) を足す - #646

Merged
5ym merged 3 commits into
mainfrom
feat/talos-ingress-firewall
Oct 31, 2026
Merged

5ym merged 3 commits into
mainfrom
feat/talos-ingress-firewall

Conversation

@5ym

@5ym 5ym commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

別の回線から、ノードの公開 IPv4 (DMZ で全部 10.0.0.2 へ) に、外に出すべきでないホストのポートが TCP でつながった: 50000/50001 (apid/trustd)・2379/2380 (etcd)・10250 (kubelet)・4240/4244 (Cilium health/Hubble)・9963/9964 (operator/envoy の metrics)。IPv6 もホスト公開で同じ。docs/router.md と recovery/README.md の「Talos の API は LAN からしか届かない」は誤りだった。

  • bootstrap/talos.sops.yaml に NetworkDefaultActionConfig (ingress: block) と NetworkRuleConfig を 4 つ
    • public-tcp: 80・443・853・3129・6443・8443 を 0.0.0.0/0・::/0 から
    • public-udp: 8443・51820 を 0.0.0.0/0・::/0 から
    • private-tcp / private-udp: 1-65535 を 10/8・100.64/10 (NetBird)・fc00::/7・fe80::/10 から (Pod・Service の 10.42/10.43・fd42/fd43 もここに入る)
  • 防火壁が効くのはホスト宛て (input) だけ。hostPort (53・853・8443・3129・51820) は Cilium が Pod に転送するので通らない。表の hostPort も念のため public に書いた (53 は書かない。Cilium のポリシーで止めているまま)
  • ライブのノードの talosctl netstat -l で、ホストで受けているのは 80・443・6443 (公開) と 50000・50001・2379・2380・2383・10250・4240・4244・8472・9963・9964・169.254.116.108:53 (内側だけ) と localhost だけなのを確かめた
  • ICMP / ICMPv6 (ND・RA) は Talos が block のときも 5 個/秒まで通す。lo と確立済みの戻りも
  • SOPS: 平文の部分だけなので sops を通さずドキュメントを足し、sops: は他のドキュメントと同じもの (mac_only_encrypted)。手元の鍵で sops -d が通るのを確かめた
  • render.sh の needle に足した。CI と同じダミーで描いて valid for metal mode を確かめた
  • talos-boot: CI だけ 4 枚目の NIC (198.51.100.0/24。プライベートでないので「外」の代わり。QEMU が IPv6 の hostfwd を読まないのでこの形) を足す。外から 443 は 200、10250 は届かない、LAN (IPv4 の 10.0.0.1) から 10250 は 401 を見る。nftables の ingress の chain が drop なのも見る
  • docs/router.md・recovery/README.md を直し、bootstrap/talos.md にネットワークを変えたら --mode=try で当てる手順を足した

当てるのは手で (apply-config --mode=try --timeout 5m で確かめてから --mode=no-reboot)。

🤖 Generated with Claude Code

https://claude.ai/code/session_01T9PbUfqG4pPxus99UeLiJs

DMZ と IPv6 ホスト公開で、ノード自身が受けるもの (Talos の API 50000・trustd 50001・etcd 2379/2380・
kubelet 10250・Cilium の 4240/4244/9963/9964) が外から届いていた。NetworkDefaultActionConfig で既定を捨て、
外からは TCP 80・443・853・3129・6443・8443 と UDP 8443・51820 だけ、プライベートのアドレスからは全部を通す。
talos-boot は IPv6 の hostfwd (送信元がグローバル) で 443 が通り 10250 が通らないことを見る。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9PbUfqG4pPxus99UeLiJs
@claude

claude Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Claude finished @5ym's task in 41s —— View job


レビュー結果

  • 差分を読む (talos.sops.yaml・render.sh・talos-boot.yml・docs 3 点)
  • 観点ごとに確認する

重大な不具合は見つかりませんでした。 変更は意図どおりで、--mode=try で当てる手順も添えてあり、締め出し事故への備えとして十分です。以下は任意の指摘で、「要確認」を含みます。

不具合・設計 (要確認)

  1. private-* の許可範囲が実際の LAN より広いです (要確認)。 172.16/12・192.168/16・100.64/10・fe80::/10 は、このリポジトリで使う範囲 (10.0.0.0/24・10.10.0.0/24・NetBird・Pod/Service) を超えています。
    • 外からの送信元詐称で、private-udp (1-65535) を TCP より通りやすくしてしまう可能性があります。
    • 実害は、ルーターが WAN 側の RFC1918 送信元を落としているかに依存します。落としているなら問題ありません。
    • 絞るなら 10.0.0.0/8 と 100.64.0.0/10、fc00::/7 だけで足ります。172.16 と 192.168 は使っていないなら外せます。
    • 意図して広くしているのなら、コメントにその旨を書くと後で迷いません。
  2. hostPort が防火壁を通らない、という前提は CI で確かめていません (要確認)。 理由は Cilium eBPF の hostPort が netfilter の input より前で処理されるため、というものです。
    • 853・3129・8443・51820 は public-* にも書いてあるので、この前提が外れても落ちません。
    • 逆に、前提が外れても 53 は public-* に無いので、Cilium のポリシーだけが守っている状態になります。
    • 今回の PR のスコープ外でも構いません。ただ、53 が private-* で通ることと、外から 53 が止まることの両方を実機で見た記録があれば安心です。
  3. ノード自身の IPv6 GUA 宛ての Pod 通信 (ks.doany.io などの AAAA) は要確認です。 マスカレードされると送信元がノードの GUA になります。それが lo 経由で通るなら問題ありません。経由しないなら private-* に当たらず落ちます。--mode=try の 5 分の間に、Pod から ks/ac を IPv6 で引く確認を 1 つ入れると確実です。

CI (talos-boot.yml)

  • 外 (IPv6) から kubelet が届かない確認は、000 を期待値にしています。タイムアウトでも hostfwd の失敗でも 000 になるため、防火壁が効いている確認としてはやや弱いです。
    • 直前の 28443 の 200 で IPv6 の hostfwd 自体は生きているとわかります。
    • ただし 30250 の転送そのものは未検証です。
    • IPv4 側の 20250 が 401 なら同じ書き方で足りるので、実害は小さいです。
  • nftableschains の ingress が drop であることの確認は、構成が載ったことを確かめるよい足し方です。

セキュリティ・SOPS

  • 平文のドキュメントに、他と同じ sops: ブロックを複製しています。mac_only_encrypted なので sops -d が通る、と PR 本文にあります。
  • 暗号化する値が無く、シークレットの混入もありません。
  • 公開するポートは表と一致しています。public-tcp の 6443 は認証付きで、docs/router.md に書いてあるとおりです。

ドキュメント

  • router.md・recovery/README.md・talos.md の誤りを直し、手順も追加してあります。
  • render.sh の needle にも足してあり、整合しています。

テスト

  • 外から 443 は通り、10250 は通らない、LAN から 10250 は 401、という確認が CI にあります。肝心の正負の確認はそろっています。
  • ポート単位の網羅は CI にありません。ライブのノードで talosctl netstat -l と別回線からの確認をしたと本文にあり、運用上はそれで足ります。

総評: マージしてよいと思います。上の 1 点目だけは、意図を決めてから進めてください。

@claude

claude Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Claude finished @5ym's task in 21s —— View job


レビュー結果

重大な不具合は見つかりませんでした。 差分(talos.sops.yaml・talos-boot.yml・render.sh・docs)を読みました。実機や CI は動かしていません。

設計・セキュリティ(要確認)

  1. private-* の送信元が広めです。 bootstrap/talos.sops.yaml の 172.16/12・192.168/16・fe80::/10 は、このリポジトリの構成(10.0.0.0/24・10.10.0.0/24・Pod/Service・NetBird)では使っていないように見えます。
    • private-* は 1-65535 全部を通すので、WAN 側から RFC1918 などの送信元を詐称したパケットが届くと、防火壁を素通りします。
    • ルーターが WAN 入口で bogon を落としているなら実害はありません。
    • 100.64.0.0/10 は NetBird 用ですが、ISP が CGNAT の場合は、他の契約者からも見える範囲です。今回は公開 IPv4 とのことなので、問題にならない可能性が高いです。
    • 使わない範囲を削るか、広くしている理由を 1 行コメントに残すと、あとで迷いません。
  2. hostPort が防火壁を通らない、という前提は CI で確かめていません。 前提が外れても、853・3129・8443・51820 は public-* に書いてあるので落ちません。
    • 53 だけは public-* に無く、private-* で通る形です。外から 53 が止まることは、Cilium のポリシーが守っています。
    • 実機で、外から 53 が届かないことを確かめた記録を PR に残すと安心です。
  3. ノード自身の IPv6 GUA 宛ての Pod 通信は未確認です。 例は ks/ac の AAAA を引いて GUA に繋ぐ通信です。送信元がノードの GUA になって lo を通らないと、private-* に当たらず落ちる可能性があります。--mode=try の間に、Pod から IPv6 で引く確認を 1 つ入れてください。

テスト (talos-boot.yml)

  • 外から 443 は 200、LAN から 10250 は 401、という正負の確認がそろっています。nftableschains の ingress が drop であることの確認もよい足し方です。
  • 外から 10250 の期待値 000 は弱めです。タイムアウトでも、hostfwd(30250)の失敗でも 000 になります。28443 の 200 で WAN 側の NIC が生きているのは分かります。ただ、30250 の転送そのものは、防火壁を外した状態で届くことを見ないと確かめられません。
    • 手軽な補強としては、curl の終了コード 28(タイムアウト)と 7(接続拒否)を区別して、期待を「タイムアウト」に絞る方法があります。

その他

  • 平文のドキュメントに、他と同じ sops: ブロックを複製しています。暗号化する値が無く、シークレットの混入もありません。mac_only_encrypted で sops -d が通る、と本文にあります。
  • render.sh の needle、router.md・recovery/README.md・talos.md の訂正と手順の追加は、整合していて問題ありません。

総評: マージしてよいと思います。1 点目だけは、範囲を絞るか理由を書くか、決めてから進めてください。
· branch feat/talos-ingress-firewall

@claude

claude Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Claude finished @5ym's task in 13s —— View job


レビュー結果

最新の push (7171af8) を確認しました。重大な不具合は見つかりませんでした。 実機や CI は動かしていません。

前回までの指摘の状況

  1. private-* の送信元が広い → 解消済み。172.16/12 と 192.168/16 を private-tcp/private-udp から外し、理由をコメントに残しています。このリポジトリの構成 (10.0.0.0/8・NetBird の 100.64/10・fc00::/7) に合っています。
    • 残りの 100.64.0.0/10 と fe80::/10 は、NetBird とリンクローカルで使うので妥当です。ISP が CGNAT の場合の見え方だけ、要確認です (公開 IPv4 とのことなので、可能性は低いです)。
  2. hostPort が防火壁を通らない前提 → 未対応です。853・3129・8443・51820 は public-* にも書いてあるので、前提が外れても落ちません。53 だけは Cilium のポリシーが守っています。外から 53 が止まる確認を実機で取り、PR に記録を残すと安心です (任意)。
  3. ノード自身の IPv6 GUA 宛ての Pod 通信 → 未確認です。--mode=try の 5 分の間に、Pod から ks/ac の AAAA を引いて繋がる確認を 1 つ入れてください (要確認)。

テスト

  • 外から 10250 の期待値 000 は、タイムアウトでも hostfwd の失敗でも 000 になるため弱めです。ただ、直前の 443 が 200 で WAN 側の NIC は生きており、実害は小さいです。

総評: マージしてよいと思います。上の 3 点目は、当てる前の --mode=try で確かめてください。
· branch feat/talos-ingress-firewall

@5ym
5ym merged commit 4cffe96 into main Oct 31, 2026
5 checks passed
@5ym
5ym deleted the feat/talos-ingress-firewall branch October 31, 2026 04:15
5ym added a commit that referenced this pull request Oct 31, 2026
#646 の防火壁で、Pod からノード自身の IP の 443 番(Gateway)が conntrack の
invalid として捨てられ、Argo CD が Forgejo を読めず runner も落ちていた
(Z440 への移行で気づいた)。ingress: accept でも invalid の規則は残るので、
5 つの文書ごと外し、render.sh の needle も外す。経緯は bootstrap/talos.md。

eno4 の disable_ipv6 は Z440 に無い名前で KernelParamSpecController が失敗し続け、
後から足した sysctl が当たらなかったので消す。


Claude-Session: https://claude.ai/code/session_01T9PbUfqG4pPxus99UeLiJs

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant