[{"data":1,"prerenderedAt":414},["ShallowReactive",2],{"blog-ja-k3s-networkpolicy-dual-stack-kube-router-ipv6-gap":3,"blog-related-ja-k3s-networkpolicy-dual-stack-kube-router-ipv6-gap":355,"blog-ja-k3s-networkpolicy-dual-stack-kube-router-ipv6-gap-alt":343},{"id":4,"title":5,"author":6,"body":7,"date":337,"description":338,"extension":339,"image":340,"locale":341,"meta":342,"navigation":343,"path":344,"seo":345,"stem":346,"tags":347,"__hash__":354},"blog\u002Fblog\u002Fja\u002Fk3s-networkpolicy-dual-stack-kube-router-ipv6-gap.md","「K3sはNetworkPolicyを無視する」は嘘だった。それでも通信が漏れていた、ServiceLBという死角","Kubo Team",{"type":8,"value":9,"toc":323},"minimark",[10,15,23,43,46,50,64,77,90,94,100,112,137,150,153,159,166,171,190,193,222,226,232,238,253,289,297,301,304],[11,12,14],"h2",{"id":13},"deny-allのnetworkpolicyを書いたのに外からの通信だけ普通に通ってしまった","deny-allのNetworkPolicyを書いたのに、外からの通信だけ普通に通ってしまった",[16,17,18],"p",{},[19,20],"img",{"alt":21,"src":22},"section01","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-networkpolicy-dual-stack-kube-router-ipv6-gap\u002Fsection01.webp",[16,24,25,26,30,31,34,35,38,39],{},"検証環境を本番相当に近づけるため、ある名前空間に ",[27,28,29],"code",{},"podSelector: {}"," の deny-all ingress ポリシーを適用した。\nPod間の通信は狙い通り遮断された。別の名前空間からの ",[27,32,33],{},"curl"," は案の定タイムアウトする。ところが、\nService を ",[27,36,37],{},"type: LoadBalancer"," で外部公開しているエンドポイントに対して、クラスタの外から同じ疎通確認をすると、\n",[40,41,42],"strong",{},"NetworkPolicyが存在しないかのように普通にレスポンスが返ってきた。",[16,44,45],{},"k3s networkpolicy が期待通り動いていないと分かった瞬間、まず疑うのは「K3sのデフォルトCNIであるFlannelは\nNetworkPolicyを無視するから」という、よく聞く説明だろう。実際、素のFlannelにはNetworkPolicyを強制する機能が\nない。だが結論から言うと、**この説明はK3sには当てはまらない。**K3sには最初からNetworkPolicyを強制する\n仕組みが組み込まれているからだ。ではなぜ通信が漏れたのか。原因はNetworkPolicyの実装そのものではなく、\nK3s標準のLoadBalancer実装である ServiceLB の経路にあった。",[11,47,49],{"id":48},"k3sはnetworkpolicyを無視するという誤解を正す","「K3sはNetworkPolicyを無視する」という誤解を正す",[16,51,52,59,60,63],{},[53,54,58],"a",{"href":55,"rel":56},"https:\u002F\u002Fdocs.k3s.io\u002Fnetworking\u002Fnetworking-services",[57],"nofollow","K3s公式ドキュメント","によれば、K3sはFlannelに加えて\n",[40,61,62],{},"kube-routerのNetworkPolicyコントローラをライブラリとして内蔵し、デフォルトで有効化","している。\nkube-router自体の他の機能（BGP等）は使わず、NetworkPolicyを強制するコントローラ部分だけを取り込んでいる形だ。\nつまりK3sクラスタを構築した時点で、追加のCNIを何もインストールしなくても、NetworkPolicyリソースをapplyすれば\nその内容が実際に反映される。「K3s = Flannelだから NetworkPolicy は無視される」という単純化は誤りで、\nこれはむしろ一般的なFlannel単体構成（例えばkubeadmで素のFlannelだけを入れた場合)との重要な違いだ。",[16,65,66,67,70,71,76],{},"この内蔵コントローラを無効化したい場合は、サーバー起動時に ",[27,68,69],{},"--disable-network-policy"," を明示的に指定する\n必要がある。",[53,72,75],{"href":73,"rel":74},"https:\u002F\u002Fdocs.k3s.io\u002Fnetworking\u002Fbasic-network-options",[57],"K3sのネットワークオプション公式ドキュメント","\nでは、Calico や Cilium のような独自のポリシーエンジンを持つCNIに切り替える際は、内蔵コントローラとの\n競合を避けるためにこのフラグを併用することが推奨されている。",[16,78,79,80,83,84,89],{},"つまり検証環境で deny-all ポリシーが",[40,81,82],{},"部分的に","効いていたという事実そのものが、\nK3sの内蔵コントローラが正常に動作している証拠でもある。問題はコントローラの有無ではなく、\n別のところにあった。こうした「デフォルトで何が有効になっているか」を都度ドキュメントで確認する作業自体が、\n自前でK3sクラスタを運用する上での地味なコストになる。",[53,85,88],{"href":86,"rel":87},"https:\u002F\u002Fkubo.hexabase.io\u002F",[57],"Kubo"," のようなマネージド\nK3sであれば、この種のデフォルト構成の確認・検証はプラットフォーム側の責務として吸収できる。",[11,91,93],{"id":92},"真犯人はservicelbnetworkpolicy-apiにはノード自身からの通信を遮断できないという制約がある","真犯人はServiceLB。NetworkPolicy APIには「ノード自身からの通信」を遮断できないという制約がある",[16,95,96],{},[19,97],{"alt":98,"src":99},"section02","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-networkpolicy-dual-stack-kube-router-ipv6-gap\u002Fsection02.webp",[16,101,102,107,108,111],{},[53,103,106],{"href":104,"rel":105},"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fservices-networking\u002Fnetwork-policies\u002F",[57],"Kubernetes公式ドキュメントのNetworkPolicyページ","\nには、あまり知られていないが重要な一文がある。",[40,109,110],{},"Podはlocalhostへのアクセスをブロックできず、\n自分が乗っているノード自身からのアクセスも原理的にブロックする手段を持たない","、という記述だ。\nこれはK3s固有の制約ではなく、Kubernetes の NetworkPolicy API そのものが持つ恒久的な仕様であり、\nどのCNI・どのポリシーコントローラを使っても解消できない。",[16,113,114,115,118,119,121,122,125,126,131,132,136],{},"この仕様がK3sで特に顕在化しやすい理由は、K3sの標準LoadBalancer実装である ",[40,116,117],{},"ServiceLB","（旧称 Klipper LB)\nの動き方にある。",[27,120,37],{}," のServiceを作成すると、ServiceLBは各ノード上に\nDaemonSetのPodをデプロイし、そのPodが",[40,123,124],{},"ノード自身のiptablesにDNATルールを書き込んで","、\nホストポート宛のトラフィックをServiceのClusterIPへ転送する仕組みになっている\n（",[53,127,130],{"href":128,"rel":129},"https:\u002F\u002Fgithub.com\u002Fk3s-io\u002Fk3s\u002Fdiscussions\u002F9927",[57],"What does ServiceLB (Klipper LB) actually do? · Discussion #9927","、\n",[53,133,135],{"href":55,"rel":134},[57],"Networking Services | K3s","）。",[16,138,139,140,143,144,149],{},"つまりLoadBalancer経由で届いたトラフィックは、Pod側から見ると**「ノード自身が転送してきた通信」**に\n分類されうる。先述の「ノード資格の通信はブロックできない」という制約と組み合わさることで、\n外部からLoadBalancer経由で届いたトラフィックに対して、NetworkPolicyのingress拒否ルールが\n期待通りに機能しないケースが生まれる。実際に、あるK3sユーザーが ",[27,141,142],{},"ipBlock"," を使った拒否ルールで\nLoadBalancer Service へのアクセスを遮断しようとしたが効かなかった、という事例が\n",[53,145,148],{"href":146,"rel":147},"https:\u002F\u002Fgithub.com\u002Fk3s-io\u002Fk3s\u002Fissues\u002F7624",[57],"K3sのIssue #7624"," に報告されている。\n同じ構成をAWS EKSで試したところ意図通りブロックできたという報告もあり、\nLoadBalancerの実装方式がNetworkPolicyの実効性に影響することを裏付けている。",[11,151,152],{"id":152},"気づくための検証手順",[16,154,155],{},[19,156],{"alt":157,"src":158},"section03","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-networkpolicy-dual-stack-kube-router-ipv6-gap\u002Fsection03.webp",[16,160,161,162,165],{},"この種の問題は ",[27,163,164],{},"kubectl get networkpolicy"," を見ても異常なく表示され、apply もエラーなく通る。\n静かに漏れるからこそ厄介だ。以下の手順で切り分けると気づきやすい。",[167,168,170],"h3",{"id":169},"pod間通信とloadbalancer経由通信を分けて確認する","Pod間通信とLoadBalancer経由通信を分けて確認する",[172,173,174,181,187],"ul",{},[175,176,177,180],"li",{},[40,178,179],{},"同一クラスタ内の別Podから"," 対象Podへ直接アクセスし、NetworkPolicyで遮断されることを確認する",[175,182,183,186],{},[40,184,185],{},"クラスタ外から、LoadBalancer Service経由で"," 同じPodへアクセスし、遮断されるかどうかを比較する",[175,188,189],{},"後者だけ通ってしまう場合、原因はNetworkPolicyの設定ミスではなく、経路自体がポリシー評価の対象外に\nなっている可能性が高い",[167,191,192],{"id":192},"ノード上のiptablesルールを確認する",[16,194,195,196,199,200,203,204,207,208,213,214,217,218,221],{},"kube-routerが書き込んだNetworkPolicy関連のiptablesルールと、ServiceLBが書き込んだDNATルールは\n別々のチェーンに存在する。対象ノードで ",[27,197,198],{},"iptables-save"," を実行し、",[27,201,202],{},"KUBE-ROUTER"," プレフィックスの\nチェーンと、ServiceLB(",[27,205,206],{},"svc-"," プレフィックスのPodが管理する)DNATルールの両方を確認することで、\nどちらの経路をトラフィックが通っているかを追跡できる。",[53,209,212],{"href":210,"rel":211},"https:\u002F\u002Fwww.kube-router.io\u002Fdocs\u002Ftroubleshoot\u002F",[57],"kube-router公式のトラブルシューティングガイド","\nによれば、NetworkPolicyによって拒否されたトラフィックは ",[27,215,216],{},"iptables"," の ",[40,219,220],{},"NFLOG group 100"," に\n記録される仕組みになっており、実際に拒否ログが記録されているか・記録されていないのに通信が\n成立しているかを見比べることでも、経路の切り分けができる。",[11,223,225],{"id":224},"対処法-l7での制御または別cniへの切り替え","対処法 — L7での制御、または別CNIへの切り替え",[16,227,228],{},[19,229],{"alt":230,"src":231},"section04","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-networkpolicy-dual-stack-kube-router-ipv6-gap\u002Fsection04.webp",[16,233,234,237],{},[40,235,236],{},"選択肢1: L4のNetworkPolicyに頼らず、L7で制御する","\nIngressコントローラやService Meshのアクセス制御機能を使えば、送信元IPやパスベースでより柔軟に\n制限できる。ノード資格通信の制約を回避しつつ、外部公開エンドポイントへのアクセス制御を実現できる。",[16,239,240,243,244,247,248,136],{},[40,241,242],{},"選択肢2: NetworkPolicy機能がより高度なCNIへ切り替える","\nCalicoのGlobalNetworkPolicyなど、より高度なポリシーエンジンを持つCNIに切り替える方法もある。\nその場合は ",[27,245,246],{},"--flannel-backend=none --disable-network-policy"," を明示的に指定し、内蔵のkube-router\nコントローラと競合しないようにする（",[53,249,252],{"href":250,"rel":251},"https:\u002F\u002Fgithub.com\u002Fk3s-io\u002Fk3s\u002Fissues\u002F1308",[57],"Issue #1308",[16,254,255,256,259,260,265,266,269,270,272,273,276,277,282,283,288],{},"ただし切り替え時には注意点がある。",[40,257,258],{},"network policy controllerを無効化しても、それまでに\nkube-routerが書き込んだiptablesルールは自動的にはクリーンアップされない","\n（",[53,261,264],{"href":262,"rel":263},"https:\u002F\u002Fgithub.com\u002Fk3s-io\u002Fk3s\u002Fissues\u002F7244",[57],"Issue #7244","）。古いルールが残ったまま新しいCNIの\nルールが追加されると、意図しない通信可否が発生しうる。",[27,267,268],{},"k3s-killall.sh"," の実行や ",[27,271,198],{},"\u002F\n",[27,274,275],{},"iptables-restore"," による手動クリーンアップを、切り替え手順に必ず組み込む必要がある。\nkube-routerのNetworkPolicyコントローラの実装詳細は\n",[53,278,281],{"href":279,"rel":280},"https:\u002F\u002Fwww.kube-router.io\u002Fdocs\u002Fuser-guide\u002F",[57],"kube-router公式ユーザーガイド","、K3sにおける\nNetworkPolicy運用の基本的な考え方は",[53,284,287],{"href":285,"rel":286},"https:\u002F\u002Fwww.suse.com\u002Fc\u002Francher_blog\u002Fk3s-network-policy\u002F",[57],"SUSE\u002FRancher公式ブログ","\nにもまとまっている。",[16,290,291,292,296],{},"こうしたCNI切り替え作業の手順そのものを個別のクラスタごとに確立し、iptablesの残骸まで含めて検証するのは\n運用負荷が高い。",[53,293,295],{"href":86,"rel":294},[57],"Kubo Cloud"," はCaptain UIでCNI構成とNetworkPolicyの\n強制状態を可視化した状態で提供しており、こうした切り替え判断を都度ゼロから検証する必要がない。",[11,298,300],{"id":299},"まとめ-デフォルトで安全という思い込みを経路ごとに検証する","まとめ — 「デフォルトで安全」という思い込みを、経路ごとに検証する",[16,302,303],{},"K3sはNetworkPolicyを無視しない。それどころかkube-routerの内蔵コントローラによって、追加の設定なしで\nNetworkPolicyが機能する数少ないディストリビューションの一つだ。しかし「NetworkPolicyが有効」であることと\n「すべての通信経路がその対象になっている」ことは別の話だ。今回のケースでは、K3s標準のServiceLBが\nノードのiptables経由でトラフィックを転送する実装であることと、NetworkPolicy APIがノード資格通信を\n原理的にブロックできないという恒久的な制約が重なったことで、外部公開したサービスへの通信だけが\n静かに漏れていた。",[16,305,306,307,310,311,316,317,322],{},"こうした「経路ごとの見落とし」は、構成を自前で組み上げるほど発生しやすい。",[53,308,88],{"href":86,"rel":309},[57],"\nはK3sベースのマネージドKubernetesとして、CNI構成やNetworkPolicyの強制範囲を運用チームが個別に\n検証しなくても済む状態で提供することを目指している。特にデータ主権やネットワーク隔離の要件が厳しい\n環境では、",[53,312,315],{"href":313,"rel":314},"https:\u002F\u002Fwww.hexabase.com\u002Fproduct\u002Fkubo\u002Fon-premise",[57],"Kubo On-Premise"," を使えば、\n自社インフラ上でも同様に検証済みの構成をそのまま利用できる。「デフォルトで安全なはず」という前提を\n経路単位で疑う習慣は、K3sに限らずKubernetes運用全般で有効な視点だ。ネットワーク構成の検証コストを\n下げたい場合は、",[53,318,321],{"href":319,"rel":320},"https:\u002F\u002Fwww.hexabase.com\u002Fcontact-us\u002F",[57],"お問い合わせ"," から相談してみてほしい。",{"title":324,"searchDepth":325,"depth":325,"links":326},"",2,[327,328,329,330,335,336],{"id":13,"depth":325,"text":14},{"id":48,"depth":325,"text":49},{"id":92,"depth":325,"text":93},{"id":152,"depth":325,"text":152,"children":331},[332,334],{"id":169,"depth":333,"text":170},3,{"id":192,"depth":333,"text":192},{"id":224,"depth":325,"text":225},{"id":299,"depth":325,"text":300},"2026-09-24","K3sはkube-router内蔵コントローラでNetworkPolicyをデフォルト強制する。それでもLoadBalancer経由の通信だけが漏れる理由は、ServiceLBの実装とNetworkPolicy APIの恒久的な制約が組み合わさった結果だった。検証手順と対処法を解説する。","md","https:\u002F\u002Fcdn.kubo.hexabase.io\u002Fimages\u002Fblog\u002Fja\u002Fk3s-networkpolicy-dual-stack-kube-router-ipv6-gap\u002Ftitle.webp","ja",{},true,"\u002Fblog\u002Fja\u002Fk3s-networkpolicy-dual-stack-kube-router-ipv6-gap",{"title":5,"description":338},"blog\u002Fja\u002Fk3s-networkpolicy-dual-stack-kube-router-ipv6-gap",[348,349,350,351,352,353],"k3s","kubernetes","networkpolicy","servicelb","kube-router","network-security","TI_HOe6j8vlT2P9OZmuBalhBAAaPn5TPi2NR5O67B7I",[356,367,376,385,394,404],{"path":357,"title":358,"description":359,"date":360,"tags":361},"\u002Fblog\u002Fja\u002Fk3s-vs-kubernetes-cni-flannel-default-comparison","K3s vs 標準Kubernetes、CNIの出発点はここまで違う。Flannel標準搭載とCNI選択制が生む差","K3sはFlannelをデフォルト同梱し、標準KubernetesはCNI未選定の状態から始まる。この出発点の違いがNetworkPolicyの可否や通信性能にどう影響するかを、K3s\u002FKubernetes\u002FCalico\u002FCiliumの公式ドキュメントをもとに比較・解説する。","2026-10-20",[348,349,362,363,364,365,350,366],"cni","flannel","calico","cilium","networking",{"path":368,"title":369,"description":370,"date":371,"tags":372},"\u002Fblog\u002Fja\u002Fk3s-pod-security-admission-restricted-servicelb-outage","restrictedを有効にしたらServiceLBが死んだ。K3sのPod Security Admissionに潜む、汎用ガイドにない設定差分","K3sでPod Security Admissionのrestrictedプロファイルを有効化したら、標準Kubernetesのガイド通りに進めたのにServiceLBが機能停止した。原因と安全な導入手順をK3s公式ハードニングガイドの記述とともに解説する。","2026-10-16",[348,349,373,374,351,375],"pod-security-admission","pod-security-standards","security",{"path":377,"title":378,"description":379,"date":380,"tags":381},"\u002Fblog\u002Fja\u002Fk3s-cert-manager-servicelb-http01-challenge-renewal-failure","K3sでcert-managerの証明書が自動更新されない。HTTP-01チャレンジをServiceLBが奪っていた","K3sでcert-managerの証明書が更新されない原因はTraefikでもcert-manager自体でもなく、port 80\u002F443を専有するServiceLBだった。HTTP-01チャレンジが静かに失敗する仕組みと恒久対処を解説する。","2026-09-25",[348,349,382,351,383,384],"cert-manager","tls","lets-encrypt",{"path":386,"title":387,"description":388,"date":389,"tags":390},"\u002Fblog\u002Fja\u002Fk3s-traefik-servicelb-ingress-nginx-port-conflict","K3sのTraefikを無効化したはずなのに、ingress-nginxが443番を取れない。ServiceLBという見えない同居人","K3sでTraefik無効化を実行したのにingress-nginxが443番ポートを取れない――原因はServiceLB(klipper-lb)というもう一つのデフォルトコンポーネント。診断から正しい無効化手順、MetalLB併用時の注意まで解説する。","2026-09-19",[348,349,391,351,392,393],"traefik","ingress-nginx","load-balancer",{"path":395,"title":396,"description":397,"date":398,"tags":399},"\u002Fblog\u002Fja\u002Fk3s-hpa-containerresource-sidecar-utilization-dilution","HPAがサイドカーの分まで合算してスケールしていた。KubernetesのContainerResourceという盲点","KubernetesのHPAはPod内の全コンテナの使用量を合算して利用率を計算するため、Istioサイドカーやログエージェントの負荷が判定を薄める。ContainerResourceメトリクスで解決する方法をK3s\u002FKubo文脈で解説する。","2026-10-21",[348,349,400,401,402,403],"hpa","containerresource","autoscaling","service-mesh",{"path":405,"title":406,"description":407,"date":408,"tags":409},"\u002Fblog\u002Fja\u002Fk3s-topology-spread-constraints-poddisruptionbudget-node-drain-pending","ノードをdrainしたらPodがPendingのまま戻らなかった。K3sでTopology Spread ConstraintsとPodDisruptionBudgetが衝突する理由","K3s本番でノードをdrainしたら一部PodがPendingのまま戻らなかった。原因はTopology Spread ConstraintsのmaxSkewとPodDisruptionBudgetの衝突。drainがノード数不足を自ら作り出す仕組みを公式ドキュメントベースで検証する。","2026-10-19",[348,349,410,411,412,413],"topology-spread-constraints","poddisruptionbudget","scheduling","node-drain",1792592609019]