From f16f214110a974b47eb8693198f1b7b9b59f9b66 Mon Sep 17 00:00:00 2001 From: Ruk Doe Date: Sat, 31 Oct 2026 12:56:52 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat(talos):=20=E3=83=8E=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=AE=E5=8F=97=E4=BF=A1=E3=81=AE=E9=98=B2=E7=81=AB=E5=A3=81?= =?UTF-8?q?=20(Ingress=20Firewall)=20=E3=82=92=E8=B6=B3=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_01T9PbUfqG4pPxus99UeLiJs --- .github/workflows/talos-boot.yml | 29 +++++- bootstrap/render.sh | 1 + bootstrap/talos.md | 9 ++ bootstrap/talos.sops.yaml | 158 +++++++++++++++++++++++++++++++ docs/router.md | 10 +- recovery/README.md | 3 +- 6 files changed, 206 insertions(+), 4 deletions(-) diff --git a/.github/workflows/talos-boot.yml b/.github/workflows/talos-boot.yml index 61b8512b..b686acb1 100644 --- a/.github/workflows/talos-boot.yml +++ b/.github/workflows/talos-boot.yml @@ -27,6 +27,8 @@ concurrency: env: # 本番と同じアドレス。SLIRP の網をこれに合わせて、machine config の住所は書き換えない NODE: 10.0.0.2 + # IPv6 の hostfwd は SLIRP の ipv6-host(240f:6d:842b:1::1。グローバルなので防火壁から見て「外」)から届く + NODE6: 240f:6d:842b:1::2 TALOSCONFIG: /tmp/out/talosconfig KUBECONFIG: /tmp/kubeconfig # 3 枚の NIC の MAC。名前は maintenance mode で MAC から引く(VM の名前は QEMU の挿し方で変わる) @@ -151,7 +153,7 @@ jobs: -device virtio-scsi-pci,id=scsi0 \ -drive file=/tmp/vm/disk.raw,format=raw,if=none,id=d0,cache=unsafe,discard=unmap \ -device scsi-hd,drive=d0,bus=scsi0.0 \ - -netdev "user,id=up,net=10.0.0.0/24,host=10.0.0.1,dhcpstart=$NODE,ipv4=on,ipv6=on,ipv6-net=240f:6d:842b:1::/64,ipv6-host=240f:6d:842b:1::1,hostfwd=tcp:127.0.0.1:50000-$NODE:50000,hostfwd=tcp:127.0.0.1:6443-$NODE:6443,hostfwd=tcp:127.0.0.1:18080-$NODE:80,hostfwd=tcp:127.0.0.1:18443-$NODE:443" \ + -netdev "user,id=up,net=10.0.0.0/24,host=10.0.0.1,dhcpstart=$NODE,ipv4=on,ipv6=on,ipv6-net=240f:6d:842b:1::/64,ipv6-host=240f:6d:842b:1::1,hostfwd=tcp:127.0.0.1:50000-$NODE:50000,hostfwd=tcp:127.0.0.1:6443-$NODE:6443,hostfwd=tcp:127.0.0.1:18080-$NODE:80,hostfwd=tcp:127.0.0.1:18443-$NODE:443,hostfwd=tcp:127.0.0.1:20250-$NODE:10250,hostfwd=tcp:[::1]:28443-[$NODE6]:443,hostfwd=tcp:[::1]:30250-[$NODE6]:10250" \ -netdev hubport,id=hub-up,hubid=0,netdev=up \ -netdev hubport,id=hub1,hubid=0 -device virtio-net-pci,netdev=hub1,mac=$MAC_ENO1 \ -netdev hubport,id=hub2,hubid=0 -device virtio-net-pci,netdev=hub2,mac=$MAC_ENO2 \ @@ -261,6 +263,24 @@ jobs: echo "::error::Gateway を通らない(http=$H https=$S。期待は 301 / 200)" exit 1 + - name: 受信の防火壁(外から 443 は通り、10250 は通らない) + timeout-minutes: 3 + run: | + set -euo pipefail + fail() { echo "::error::$*"; exit 1; } + code() { curl -s -o /dev/null -w '%{http_code}' --max-time 10 "$@" || true; } + # IPv4 の hostfwd は SLIRP の 10.0.0.1(家の LAN と同じ。private-tcp に当たる)から来る。kubelet は認証無しなら 401 + K4=$(code -k https://127.0.0.1:20250/healthz) + echo " LAN から kubelet: $K4" + [ "$K4" = 401 ] || fail "LAN から kubelet(10250)に届かない($K4。期待は 401)" + # IPv6 の hostfwd は SLIRP の 240f:6d:842b:1::1(グローバル)から来る。外から来たのと同じ扱いになる + S6=$(code -k --resolve 'ac.doany.io:28443:[::1]' https://ac.doany.io:28443/) + echo " 外(IPv6)から Gateway: $S6" + [ "$S6" = 200 ] || fail "外(IPv6)から 443 が通らない($S6)" + K6=$(code -k --max-time 5 'https://[::1]:30250/healthz') + echo " 外(IPv6)から kubelet: $K6" + [ "$K6" = 000 ] || fail "外(IPv6)から kubelet(10250)に届いた($K6)。防火壁が効いていない" + - name: ディスクとネットワーク timeout-minutes: 5 run: | @@ -278,6 +298,13 @@ jobs: [ "$GOT" = "$WANT" ] || fail "bond0 の MAC が $GOT(talos.sops.yaml は $WANT)" echo " bond0 hardwareAddr: $GOT" + # 受信の防火壁(talos.sops.yaml の NetworkDefaultActionConfig)が既定で捨てる形で載っているか。 + # 通す側は、ここまでの talosctl(50000)・kubectl(6443)・curl(80 / 443)が SLIRP の 10.0.0.1 から通ったことで見ている + talosctl get nftableschains -o yaml > /tmp/nft.yaml + P=$(yq -r 'select(.metadata.id == "ingress") | .spec.policy' /tmp/nft.yaml) + echo " nftables の ingress の既定: $P" + [ "$(echo "$P" | tr 'A-Z' 'a-z')" = drop ] || { cat /tmp/nft.yaml; fail "ingress の chain が既定で捨てる形(drop)でない"; } + # 以下は forwarding=1 のあとで見ないと意味が無い(talos.sops.yaml の accept_ra) F=$(talosctl read /proc/sys/net/ipv6/conf/bond0/forwarding) [ "$F" = 1 ] || fail "bond0 の forwarding が $F。前提が成り立っていない" diff --git a/bootstrap/render.sh b/bootstrap/render.sh index bb3a327a..2a7af6fd 100755 --- a/bootstrap/render.sh +++ b/bootstrap/render.sh @@ -238,6 +238,7 @@ for n in "kube-apiserver:$K8S" "ghcr.io/siderolabs/kubelet:$K8S" \ 'name: cilium' cilium-operator KUBERNETES_SERVICE_PORT 'value: \"7445\"' 'cgroup-root: \"/sys/fs/cgroup\"' \ 'kind: GatewayClass' io.cilium/gateway-controller \ 'kind: RawVolumeConfig' 'kind: LVMVolumeGroupConfig' 'name: dm_thin_pool' \ + 'kind: NetworkDefaultActionConfig' 'name: public-tcp' 'name: private-tcp' \ 'name: lvm-localpv' lvm-localpv-node lvm-localpv-controller 'storageCapacity: false' 'doany.io/lvm-thinpool: ready' \ 'name: storage' 'name: local-path' 'provisioner: local.csi.openebs.io' 'volgroup: data' \ 'kind: VolumeSnapshotClass' 'name: lvm-thinpool' \ diff --git a/bootstrap/talos.md b/bootstrap/talos.md index 12b72349..1bdbc5e2 100644 --- a/bootstrap/talos.md +++ b/bootstrap/talos.md @@ -65,6 +65,15 @@ needle は `render.sh` の末尾の 1 か所だけに置く。 | `talos.sops.yaml` の先頭の Kubernetes の `# version:` | `render.sh` → `apply-config` → `talosctl upgrade-k8s --to <新しい版>` | 無し | | `talos.sops.yaml` の本文と、`bootstrap/` の残りの全部(`*-values(.sops).yaml`(2 つめのドキュメントの Secret も)・`apiserver-rbac.yaml`・`storage.yaml`) | `render.sh` → `apply-config` → `talosctl upgrade-k8s --to <今の版>`(下の「inlineManifests を直したとき」) | 場合による | +**ネットワークと受信の防火壁(`BondConfig`・`LinkConfig`・`NetworkRuleConfig` など)を変えたら `--mode=try` で当てる。** +間違えると Talos の API ごと届かなくなるが、`try` なら時間内に `--mode=no-reboot` で当て直さないと元に戻る: + +```shell +talosctl apply-config --mode=try --timeout 5m -f bootstrap/clusterconfig/controlplane.yaml +# 5 分のうちに確かめる(talosctl get members・kubectl get nodes・外からの Web・DoT・NetBird)。良ければ確定させる +talosctl apply-config --mode=no-reboot -f bootstrap/clusterconfig/controlplane.yaml +``` + ### inlineManifests を直したとき **Cilium・OpenEBS LVM(`storage.yaml` も)・`apiserver-rbac.yaml`・ArgoCD・infisical・ diff --git a/bootstrap/talos.sops.yaml b/bootstrap/talos.sops.yaml index 3b4f8cc1..b05629f8 100644 --- a/bootstrap/talos.sops.yaml +++ b/bootstrap/talos.sops.yaml @@ -537,6 +537,164 @@ sops: mac_only_encrypted: true version: 3.13.3 --- +# ホスト(Talos の API・etcd・kubelet・Cilium・Gateway の Envoy など)が受けるものの防火壁(Ingress Firewall)。 +# ルーターは DMZ と IPv6 ホスト公開で全部のポートをノードに流すので(../docs/router.md)、外に出すものはここで決める。 +# 既定は捨て、下の NetworkRuleConfig に当たるものだけ通す。lo・確立済みの戻り・ICMP / ICMPv6(5 個/秒まで)・ +# Pod と Service の網どうしは Talos が自分で通す。効くのはホスト宛て(input)だけで、hostPort は Cilium が Pod へ +# 転送するのでここを通らない(Pod の手前は Cilium のポリシー。53 番は ../apps/adguardhome/network-policy.yaml)。 +# 間違えると Talos の API ごと締め出されるので、当てるときは apply-config --mode=try(talos.md「上げ方 / 当て直し方」)。 +apiVersion: v1alpha1 +kind: NetworkDefaultActionConfig +ingress: block +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIQnpITHlrS0lxZkZXb3dy + UmNMYUhFamtsR2Rpb3BTMXozYjQwQkoxOEhFClFOeDRQV2tTYTBlL09RUS9oMUZG + ZHZwNXVnYzA4dkIyME0rbnc0Zm44SEUKLS0tIDhTNmNMU1ZVeGEwbzltTDdpVVRP + M0FiWEJ2MHIzRkU2WHRxWlo3N0FsNlEKgYVZr+vTicTztpwMQ7oj/yLEk12f/JZX + uMTe29EqIoB7gE/SCG9z+qoLXd4NHrA1lfrLjTDSCYNEhGiDyMhIMQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r + encrypted_regex: ^password$ + lastmodified: "2026-10-30T16:40:35Z" + mac: ENC[AES256_GCM,data:HeBfzNkyaDPxwfMepe0/4U5g0tAUyMf9AZMYly5La46tj8Ap5K4z9jp3tcOR9tADq1nCBhgtIKDiLmrNqOOWLShV1jDVM35hpBDHMpYuJjAGish8pBZUb3TetvSa1fnzOE24JrCZxpaK69q5V9akQzKIlhM/qgRhU7jFqPhyDT8=,iv:8QW9fMoDnME0qsE/TMcpi3zKgl+Oy+9mN8jzRY7XnN4=,tag:gOxsxLzsRPBx8iQjY5RW/A==,type:str] + mac_only_encrypted: true + version: 3.13.3 +--- +# 外から要るもの(TCP)。ホストが受けるのは 80 / 443(Gateway の Envoy。hostNetwork)と 6443(ks.doany.io と +# cilium-drift.yml)。853(DoT)・3129(3proxy)・8443(LiveKit)は hostPort でここを通らないが、通る形に変わっても +# 落ちないよう書いておく。足すときは ../docs/router.md の表も。 +apiVersion: v1alpha1 +kind: NetworkRuleConfig +name: public-tcp +portSelector: + ports: + - 80 + - 443 + - 853 + - 3129 + - 6443 + - 8443 + protocol: tcp +ingress: + - subnet: 0.0.0.0/0 + - subnet: ::/0 +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIQnpITHlrS0lxZkZXb3dy + UmNMYUhFamtsR2Rpb3BTMXozYjQwQkoxOEhFClFOeDRQV2tTYTBlL09RUS9oMUZG + ZHZwNXVnYzA4dkIyME0rbnc0Zm44SEUKLS0tIDhTNmNMU1ZVeGEwbzltTDdpVVRP + M0FiWEJ2MHIzRkU2WHRxWlo3N0FsNlEKgYVZr+vTicTztpwMQ7oj/yLEk12f/JZX + uMTe29EqIoB7gE/SCG9z+qoLXd4NHrA1lfrLjTDSCYNEhGiDyMhIMQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r + encrypted_regex: ^password$ + lastmodified: "2026-10-30T16:40:35Z" + mac: ENC[AES256_GCM,data:HeBfzNkyaDPxwfMepe0/4U5g0tAUyMf9AZMYly5La46tj8Ap5K4z9jp3tcOR9tADq1nCBhgtIKDiLmrNqOOWLShV1jDVM35hpBDHMpYuJjAGish8pBZUb3TetvSa1fnzOE24JrCZxpaK69q5V9akQzKIlhM/qgRhU7jFqPhyDT8=,iv:8QW9fMoDnME0qsE/TMcpi3zKgl+Oy+9mN8jzRY7XnN4=,tag:gOxsxLzsRPBx8iQjY5RW/A==,type:str] + mac_only_encrypted: true + version: 3.13.3 +--- +# 外から要るもの(UDP)。LiveKit の 8443 と NetBird の routing peer の 51820(どちらも hostPort。上と同じく念のため)。 +# STUN は外のもの(Cloudflare)を使うので開けない。 +apiVersion: v1alpha1 +kind: NetworkRuleConfig +name: public-udp +portSelector: + ports: + - 8443 + - 51820 + protocol: udp +ingress: + - subnet: 0.0.0.0/0 + - subnet: ::/0 +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIQnpITHlrS0lxZkZXb3dy + UmNMYUhFamtsR2Rpb3BTMXozYjQwQkoxOEhFClFOeDRQV2tTYTBlL09RUS9oMUZG + ZHZwNXVnYzA4dkIyME0rbnc0Zm44SEUKLS0tIDhTNmNMU1ZVeGEwbzltTDdpVVRP + M0FiWEJ2MHIzRkU2WHRxWlo3N0FsNlEKgYVZr+vTicTztpwMQ7oj/yLEk12f/JZX + uMTe29EqIoB7gE/SCG9z+qoLXd4NHrA1lfrLjTDSCYNEhGiDyMhIMQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r + encrypted_regex: ^password$ + lastmodified: "2026-10-30T16:40:35Z" + mac: ENC[AES256_GCM,data:HeBfzNkyaDPxwfMepe0/4U5g0tAUyMf9AZMYly5La46tj8Ap5K4z9jp3tcOR9tADq1nCBhgtIKDiLmrNqOOWLShV1jDVM35hpBDHMpYuJjAGish8pBZUb3TetvSa1fnzOE24JrCZxpaK69q5V9akQzKIlhM/qgRhU7jFqPhyDT8=,iv:8QW9fMoDnME0qsE/TMcpi3zKgl+Oy+9mN8jzRY7XnN4=,tag:gOxsxLzsRPBx8iQjY5RW/A==,type:str] + mac_only_encrypted: true + version: 3.13.3 +--- +# プライベートのアドレスからは全部のポート(TCP。UDP は次)。家の LAN(10.0.0.0/24・10.10.0.0/24)・NetBird(100.64.0.0/10)・ +# Pod と Service(10.42 / 10.43・fd42 / fd43。10.0.0.0/8 と fc00::/7 に入る)。talosctl(作業用 PC から 10.10.0.4:50000)・ +# etcd・kubelet・Cilium(4240・4244・8472・9963・9964)・Pod からの Talos API(k8up)とノードの DNS(169.254.116.108:53)はここ。 +# 家の LAN の IPv6 の GUA(RA のプレフィックス。変わりうる)は入れていないので、LAN からは IPv4 で繋ぐ。 +apiVersion: v1alpha1 +kind: NetworkRuleConfig +name: private-tcp +portSelector: + ports: + - 1-65535 + protocol: tcp +ingress: + - subnet: 10.0.0.0/8 + - subnet: 172.16.0.0/12 + - subnet: 192.168.0.0/16 + - subnet: 100.64.0.0/10 + - subnet: fc00::/7 + - subnet: fe80::/10 +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIQnpITHlrS0lxZkZXb3dy + UmNMYUhFamtsR2Rpb3BTMXozYjQwQkoxOEhFClFOeDRQV2tTYTBlL09RUS9oMUZG + ZHZwNXVnYzA4dkIyME0rbnc0Zm44SEUKLS0tIDhTNmNMU1ZVeGEwbzltTDdpVVRP + M0FiWEJ2MHIzRkU2WHRxWlo3N0FsNlEKgYVZr+vTicTztpwMQ7oj/yLEk12f/JZX + uMTe29EqIoB7gE/SCG9z+qoLXd4NHrA1lfrLjTDSCYNEhGiDyMhIMQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r + encrypted_regex: ^password$ + lastmodified: "2026-10-30T16:40:35Z" + mac: ENC[AES256_GCM,data:HeBfzNkyaDPxwfMepe0/4U5g0tAUyMf9AZMYly5La46tj8Ap5K4z9jp3tcOR9tADq1nCBhgtIKDiLmrNqOOWLShV1jDVM35hpBDHMpYuJjAGish8pBZUb3TetvSa1fnzOE24JrCZxpaK69q5V9akQzKIlhM/qgRhU7jFqPhyDT8=,iv:8QW9fMoDnME0qsE/TMcpi3zKgl+Oy+9mN8jzRY7XnN4=,tag:gOxsxLzsRPBx8iQjY5RW/A==,type:str] + mac_only_encrypted: true + version: 3.13.3 +--- +# 上と同じ送信元から UDP の全部(Cilium の VXLAN 8472、ノードの DNS など)。 +apiVersion: v1alpha1 +kind: NetworkRuleConfig +name: private-udp +portSelector: + ports: + - 1-65535 + protocol: udp +ingress: + - subnet: 10.0.0.0/8 + - subnet: 172.16.0.0/12 + - subnet: 192.168.0.0/16 + - subnet: 100.64.0.0/10 + - subnet: fc00::/7 + - subnet: fe80::/10 +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIQnpITHlrS0lxZkZXb3dy + UmNMYUhFamtsR2Rpb3BTMXozYjQwQkoxOEhFClFOeDRQV2tTYTBlL09RUS9oMUZG + ZHZwNXVnYzA4dkIyME0rbnc0Zm44SEUKLS0tIDhTNmNMU1ZVeGEwbzltTDdpVVRP + M0FiWEJ2MHIzRkU2WHRxWlo3N0FsNlEKgYVZr+vTicTztpwMQ7oj/yLEk12f/JZX + uMTe29EqIoB7gE/SCG9z+qoLXd4NHrA1lfrLjTDSCYNEhGiDyMhIMQ== + -----END AGE ENCRYPTED FILE----- + recipient: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r + encrypted_regex: ^password$ + lastmodified: "2026-10-30T16:40:35Z" + mac: ENC[AES256_GCM,data:HeBfzNkyaDPxwfMepe0/4U5g0tAUyMf9AZMYly5La46tj8Ap5K4z9jp3tcOR9tADq1nCBhgtIKDiLmrNqOOWLShV1jDVM35hpBDHMpYuJjAGish8pBZUb3TetvSa1fnzOE24JrCZxpaK69q5V9akQzKIlhM/qgRhU7jFqPhyDT8=,iv:8QW9fMoDnME0qsE/TMcpi3zKgl+Oy+9mN8jzRY7XnN4=,tag:gOxsxLzsRPBx8iQjY5RW/A==,type:str] + mac_only_encrypted: true + version: 3.13.3 +--- # 外から入る CI(cilium-drift.yml の OIDC トークン)と人(Entra)の認証。権限の中身は apiserver-rbac.yaml。 apiVersion: v1alpha1 kind: KubeAuthenticationConfig diff --git a/docs/router.md b/docs/router.md index 5d992fa3..d9daa90c 100644 --- a/docs/router.md +++ b/docs/router.md @@ -42,7 +42,13 @@ DMZ の向け先を変えると、下の全部と AdGuard の split-horizon が | 3129 TCP | 3proxy の TLS 口(apps/3proxy/) | 外から使うなら要る | | 6443 TCP | Kubernetes の API(`ks.doany.io:6443`。recovery/README.md) | 要る(認証つき) | -Talos の API(50000)は LAN からしか届かない(recovery/README.md)。 +**ノード自身が受けるもの(Talos の API 50000・trustd 50001・etcd・kubelet 10250・Cilium の 4240 / 4244 / 9963 / 9964 など)は、 +ノードの受信の防火壁で外から止めている**(`bootstrap/talos.sops.yaml` の `NetworkDefaultActionConfig` と `NetworkRuleConfig`。 +2026-10-31 に足すまでは DMZ と IPv6 ホスト公開で外から全部届いていた)。既定は捨て、外から通すのは上の表のポートだけ +(TCP 80・443・853・3129・6443・8443、UDP 8443・51820)、プライベートのアドレス(10/8・172.16/12・192.168/16・NetBird の 100.64/10・ +fc00::/7・fe80::/10)からは全部。効くのはノード宛てだけで、hostPort(53・853・8443・3129・51820)は Cilium が Pod へ転送するので +通らない(なので 53 番は下の Cilium のポリシーで止めている)。表にポートを足すときは `public-tcp` / `public-udp` にも足す。 +家の LAN の IPv6 の GUA はプライベートに入れていないので、LAN からノードの管理の口へは IPv4 で繋ぐ。 ## 53 番は外に出さない @@ -60,7 +66,7 @@ AdGuard の `allowed_clients` で絞らないのは、DoT・DoH にも効いて 再起動で変わってエントリが外れる。NIC を替えても Z440 に移しても、この値は変わらない - **公開する AAAA は静的な `::2`。** cloudflare-ddns の `local.iface.stable:bond0` は一時アドレス以外から選ぶので、SLAAC のアドレスがあると そちらを書いてしまう。`bond0` は `autoconf=0`(bootstrap/talos.sops.yaml)で SLAAC を付けない -- 公開の中身は DMZ と同じ(IPv6 すべて・ポート any)。ノードで受けているものは IPv6 でも全部外に出る +- 公開の中身は DMZ と同じ(IPv6 すべて・ポート any)。ノードで受けているものは IPv6 でも外に出る(ノードの管理の口は IPv4 と同じくノードの防火壁が止める。上の「外からの転送」) - `fj` / `nb` / `m` / `ks` / `lk` などの AAAA はノード(`240f:6d:842b:1::2`)を指すので、**このエントリを消すと IPv6 の利用者から直接つなぐアプリが見えなくなる** - 確かめ方: 別の回線の IPv6 から名前で開く(アドレス直打ちは SNI が無く Gateway が切る)。J:COM 側の PC から `curl -6 -so /dev/null -w "%{http_code} %{remote_ip}\n" https://fj.doany.io/` で `200 240f:6d:842b:1::2` diff --git a/recovery/README.md b/recovery/README.md index 7c735ab7..42fca0b5 100644 --- a/recovery/README.md +++ b/recovery/README.md @@ -50,7 +50,8 @@ talosconfig も管理者の kubeconfig も `bootstrap/talos-secrets.sops.yaml` - **作業用 PC(J:COM 側の LAN)からは 10.10.0.4(eno4)にしか届かない**(10.0.0.2 は届かない)。t.ps1 の行き先はそこに固定してある - iLO(10.0.0.3)の Remote Console(HTML5)で、ブートメニューも maintenance mode の IP も見える。USB だけ物理で挿す -- **GitHub Actions では代わりにならない。** Talos の API(50000)は LAN からしか届かず、CI の OIDC の信頼も +- **GitHub Actions では代わりにならない。** Talos の API(50000)は machine config の受信の防火壁でプライベートのアドレスからしか通さず + ([../docs/router.md](../docs/router.md)「外からの転送」。maintenance mode では防火壁が無い)、CI の OIDC の信頼も machine config を当てて初めてできる ## 1. 鍵を開いて machine config を描く From 6981355b65e1a62d10aaa7f25ef8ac90c453b6cd Mon Sep 17 00:00:00 2001 From: Ruk Doe Date: Sat, 31 Oct 2026 12:59:57 +0900 Subject: [PATCH 2/3] =?UTF-8?q?ci(talos-boot):=20=E5=A4=96=E3=81=AE?= =?UTF-8?q?=E4=BB=A3=E3=82=8F=E3=82=8A=E3=81=AB=20198.51.100.0/24=20?= =?UTF-8?q?=E3=81=AE=204=20=E6=9E=9A=E7=9B=AE=E3=81=AE=20NIC=20=E3=81=A7?= =?UTF-8?q?=E9=98=B2=E7=81=AB=E5=A3=81=E3=82=92=E8=A6=8B=E3=82=8B=20(QEMU?= =?UTF-8?q?=20=E3=81=8C=20IPv6=20=E3=81=AE=20hostfwd=20=E3=82=92=E8=AA=AD?= =?UTF-8?q?=E3=81=BE=E3=81=AA=E3=81=84)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01T9PbUfqG4pPxus99UeLiJs --- .github/workflows/talos-boot.yml | 40 +++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/.github/workflows/talos-boot.yml b/.github/workflows/talos-boot.yml index b686acb1..e5912ec3 100644 --- a/.github/workflows/talos-boot.yml +++ b/.github/workflows/talos-boot.yml @@ -27,8 +27,9 @@ concurrency: env: # 本番と同じアドレス。SLIRP の網をこれに合わせて、machine config の住所は書き換えない NODE: 10.0.0.2 - # IPv6 の hostfwd は SLIRP の ipv6-host(240f:6d:842b:1::1。グローバルなので防火壁から見て「外」)から届く - NODE6: 240f:6d:842b:1::2 + # 受信の防火壁を「外」から見るための 4 枚目の NIC(CI だけ)。198.51.100.0/24 は文書用でプライベートでない + WAN_NODE: 198.51.100.2 + MAC_WAN: 52:54:00:00:00:05 TALOSCONFIG: /tmp/out/talosconfig KUBECONFIG: /tmp/kubeconfig # 3 枚の NIC の MAC。名前は maintenance mode で MAC から引く(VM の名前は QEMU の挿し方で変わる) @@ -153,12 +154,14 @@ jobs: -device virtio-scsi-pci,id=scsi0 \ -drive file=/tmp/vm/disk.raw,format=raw,if=none,id=d0,cache=unsafe,discard=unmap \ -device scsi-hd,drive=d0,bus=scsi0.0 \ - -netdev "user,id=up,net=10.0.0.0/24,host=10.0.0.1,dhcpstart=$NODE,ipv4=on,ipv6=on,ipv6-net=240f:6d:842b:1::/64,ipv6-host=240f:6d:842b:1::1,hostfwd=tcp:127.0.0.1:50000-$NODE:50000,hostfwd=tcp:127.0.0.1:6443-$NODE:6443,hostfwd=tcp:127.0.0.1:18080-$NODE:80,hostfwd=tcp:127.0.0.1:18443-$NODE:443,hostfwd=tcp:127.0.0.1:20250-$NODE:10250,hostfwd=tcp:[::1]:28443-[$NODE6]:443,hostfwd=tcp:[::1]:30250-[$NODE6]:10250" \ + -netdev "user,id=up,net=10.0.0.0/24,host=10.0.0.1,dhcpstart=$NODE,ipv4=on,ipv6=on,ipv6-net=240f:6d:842b:1::/64,ipv6-host=240f:6d:842b:1::1,hostfwd=tcp:127.0.0.1:50000-$NODE:50000,hostfwd=tcp:127.0.0.1:6443-$NODE:6443,hostfwd=tcp:127.0.0.1:18080-$NODE:80,hostfwd=tcp:127.0.0.1:18443-$NODE:443,hostfwd=tcp:127.0.0.1:20250-$NODE:10250" \ -netdev hubport,id=hub-up,hubid=0,netdev=up \ -netdev hubport,id=hub1,hubid=0 -device virtio-net-pci,netdev=hub1,mac=$MAC_ENO1 \ -netdev hubport,id=hub2,hubid=0 -device virtio-net-pci,netdev=hub2,mac=$MAC_ENO2 \ -netdev user,id=lan10,net=10.10.0.0/24,host=10.10.0.1,ipv6=off,restrict=on \ -device virtio-net-pci,netdev=lan10,mac=$MAC_ENO4 \ + -netdev "user,id=wan,net=198.51.100.0/24,host=198.51.100.1,ipv6=off,restrict=on,hostfwd=tcp:127.0.0.1:28443-$WAN_NODE:443,hostfwd=tcp:127.0.0.1:30250-$WAN_NODE:10250" \ + -device virtio-net-pci,netdev=wan,mac=$MAC_WAN \ -display none -serial file:/tmp/vm/serial.log \ -daemonize -pidfile /tmp/vm/qemu.pid @@ -174,6 +177,21 @@ jobs: # NIC は MAC で選ぶ(LinkAliasConfig)ので、実機の MAC を VM の MAC に差し替える。sysctl はカーネルの名前で書くので名前も sed -e "s/30:e1:71:60:fe:a8/$MAC_ENO1/g" -e "s/30:e1:71:60:fe:a9/$MAC_ENO2/g" -e "s/30:e1:71:60:fe:ab/$MAC_ENO4/g" \ -e "s/\beno4\b/$N4/g" /tmp/out/controlplane.yaml > /tmp/vm/controlplane.yaml + # 4 枚目(外の代わり)に住所を付ける。本物の config には無い + cat >> /tmp/vm/controlplane.yaml < Date: Sat, 31 Oct 2026 13:01:07 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix(talos):=20=E5=86=85=E5=81=B4=E3=81=AE?= =?UTF-8?q?=E9=80=81=E4=BF=A1=E5=85=83=E3=82=92=E4=BD=BF=E3=81=86=E3=82=82?= =?UTF-8?q?=E3=81=AE=E3=81=A0=E3=81=91=E3=81=AB=E3=81=99=E3=82=8B=20(172.1?= =?UTF-8?q?6/12=E3=83=BB192.168/16=20=E3=82=92=E5=A4=96=E3=81=99)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01T9PbUfqG4pPxus99UeLiJs --- bootstrap/talos.sops.yaml | 5 +---- docs/router.md | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/bootstrap/talos.sops.yaml b/bootstrap/talos.sops.yaml index b05629f8..754e2b49 100644 --- a/bootstrap/talos.sops.yaml +++ b/bootstrap/talos.sops.yaml @@ -632,6 +632,7 @@ sops: # Pod と Service(10.42 / 10.43・fd42 / fd43。10.0.0.0/8 と fc00::/7 に入る)。talosctl(作業用 PC から 10.10.0.4:50000)・ # etcd・kubelet・Cilium(4240・4244・8472・9963・9964)・Pod からの Talos API(k8up)とノードの DNS(169.254.116.108:53)はここ。 # 家の LAN の IPv6 の GUA(RA のプレフィックス。変わりうる)は入れていないので、LAN からは IPv4 で繋ぐ。 +# 172.16/12・192.168/16 は使っていないので入れない(使うものだけ。足すなら上の送信元を増やしたとき)。 apiVersion: v1alpha1 kind: NetworkRuleConfig name: private-tcp @@ -641,8 +642,6 @@ portSelector: protocol: tcp ingress: - subnet: 10.0.0.0/8 - - subnet: 172.16.0.0/12 - - subnet: 192.168.0.0/16 - subnet: 100.64.0.0/10 - subnet: fc00::/7 - subnet: fe80::/10 @@ -673,8 +672,6 @@ portSelector: protocol: udp ingress: - subnet: 10.0.0.0/8 - - subnet: 172.16.0.0/12 - - subnet: 192.168.0.0/16 - subnet: 100.64.0.0/10 - subnet: fc00::/7 - subnet: fe80::/10 diff --git a/docs/router.md b/docs/router.md index d9daa90c..7b30954b 100644 --- a/docs/router.md +++ b/docs/router.md @@ -45,7 +45,7 @@ DMZ の向け先を変えると、下の全部と AdGuard の split-horizon が **ノード自身が受けるもの(Talos の API 50000・trustd 50001・etcd・kubelet 10250・Cilium の 4240 / 4244 / 9963 / 9964 など)は、 ノードの受信の防火壁で外から止めている**(`bootstrap/talos.sops.yaml` の `NetworkDefaultActionConfig` と `NetworkRuleConfig`。 2026-10-31 に足すまでは DMZ と IPv6 ホスト公開で外から全部届いていた)。既定は捨て、外から通すのは上の表のポートだけ -(TCP 80・443・853・3129・6443・8443、UDP 8443・51820)、プライベートのアドレス(10/8・172.16/12・192.168/16・NetBird の 100.64/10・ +(TCP 80・443・853・3129・6443・8443、UDP 8443・51820)、内側のアドレス(LAN と Pod・Service の 10/8・NetBird の 100.64/10・ fc00::/7・fe80::/10)からは全部。効くのはノード宛てだけで、hostPort(53・853・8443・3129・51820)は Cilium が Pod へ転送するので 通らない(なので 53 番は下の Cilium のポリシーで止めている)。表にポートを足すときは `public-tcp` / `public-udp` にも足す。 家の LAN の IPv6 の GUA はプライベートに入れていないので、LAN からノードの管理の口へは IPv4 で繋ぐ。