ingress-nginx の保守終了と IngressNightmare、移行先の比較と k3s での Traefik への切り替え
microk8s をインストールしたまま運用していると、snap の自動更新で新しくなっていると思いがちだが、そうはならない。snap はインストール時に指定したチャネル (1.24/stable など) を追従し、そのチャネル内のパッチ版しか入れない。マイナーバージョンは手で snap refresh --channel= しない限り上がらない。
$ snap list microk8s
Name Version Rev Tracking Publisher Notes
microk8s v1.24.17 5872 1.24/stable canonical** classic
1.24 の upstream サポートは 2023 年 7 月に終わっている。古い microk8s や k3s を上げようとすると、Kubernetes 本体より Ingress コントローラーのほうが大きな問題になる。microk8s の ingress addon の中身であり、k3s でもよく使われてきた ingress-nginx の保守が終了したためである。
ingress-nginx の保守終了
ここで言う ingress-nginx は、Kubernetes コミュニティが開発していた kubernetes/ingress-nginx である。F5 社 (nginx 社) が開発している nginx/kubernetes-ingress とは別物で、名前が似ているので注意が必要だ。
2025 年 11 月 11 日、Kubernetes 公式ブログが Ingress NGINX Retirement: What You Need to Know でリタイアを告知した。内容は次のとおり。
- 2026 年 3 月まで best-effort で保守し、その後はリリース、バグ修正、脆弱性修正のいずれも行わない
- 既存のコンテナイメージと Helm chart は削除されない。今動いているものが止まることはない
- 移行先として Gateway API の実装か、他の Ingress コントローラーを推奨する
最終リリースは 2026 年 3 月 19 日の controller-v1.15.1 で、対応する Kubernetes は 1.31〜1.35 である。1.36 は公式のテスト対象に入っていない。
リタイアの理由
理由は人手不足と、設計に由来するセキュリティ上の負債である。
- 利用者は多かったが、何年も 1〜2 人のメンテナが業務時間外のボランティアで保守していた。メンテナの募集にも人が集まらなかった
server-snippetやconfiguration-snippetのように、annotation から nginx の設定を直接書ける仕組みが特長だった。この仕組みのせいで「Ingress を作れる者はコントローラーを乗っ取れる」という構造になっていた。コントローラーは全 namespace の Secret を読む権限を持つ- 根本的な解決には作り直しが必要だった。後継として Gateway API ベースの InGate が計画されたが、こちらも人が集まらずに打ち切られた
セキュリティ上の問題
IngressNightmare (CVE-2025-1974 ほか)
2025 年 3 月に Wiz Research が公表した脆弱性群で、CVE-2025-1974 の CVSS は 9.8 である。
- 入口は ingress-nginx の admission webhook (Ingress を作る前に内容を検証する仕組み) で、Pod ネットワークから認証なしで到達できる
- 細工した Ingress を webhook に送り、annotation 経由で nginx の設定を注入する (CVE-2025-1097 / CVE-2025-1098 / CVE-2025-24514 など)
- webhook は検証のために生成した設定で
nginx -tを実行する。このとき注入した設定が読まれ、別途アップロードしておいた共有ライブラリがロードされて、コントローラー内で任意のコードが実行される - コントローラーは全 namespace の Secret を読めるので、クラスタ全体の乗っ取りにつながる
修正版は v1.11.5 と v1.12.1 である。Wiz はクラウド環境の約 4 割が影響を受けると推定していた。
同じ系統の過去の脆弱性
annotation の値がそのまま nginx の設定に埋め込まれることによる注入は、以前から繰り返し見つかっていた。
| CVE | 内容 |
|---|---|
| CVE-2021-25742 | *-snippet annotation から Secret を読み出せた |
| CVE-2022-4886 | path の検査をすり抜けられた |
| CVE-2023-5043 / CVE-2023-5044 | configuration-snippet / permanent-redirect による設定注入 |
個別の穴を塞いでも、同じ種類の穴が次に見つかる。この設計上の問題が、リタイアの理由の 1 つになっている。
ディストリビューション側の対応
microk8s は 1.35 のリリースノートで ingress addon を NGINX から Traefik に置き換えた。1.35 / 1.36 の addon スクリプト (canonical/microk8s-core-addons の addons/ingress/enable) は Traefik を Helm で入れる処理だけで、NGINX を選ぶオプションは無い。community addon にも NGINX 系は無い。
k3s は以前から同梱の Ingress コントローラーが Traefik である。
Kubernetes の upstream サポート期限は次のとおりで、1.34 は記事執筆時点 (2026 年 10 月) で残り 1 週間ほどである。
| バージョン | サポート終了 |
|---|---|
| 1.34 | 2026-10-27 |
| 1.35 | 2027-02-28 |
| 1.36 | 2027-06-28 |
これから上げるなら 1.35 以上が目標になる。microk8s を 1.35 以上にすると、ingress-nginx を addon で使い続けることはできない。
移行先の比較
候補を並べた。
| 案 | 内容 | 弱点 |
|---|---|---|
| Traefik (ディストリビューション同梱) | microk8s / k3s の既定。本体と一緒に更新される | nginx の生設定を書けない。server-snippet 相当の処理は Middleware で表現できる範囲に限られる。entrypoint の既定 readTimeout が 60 秒 |
| F5 NGINX Ingress Controller (OSS 版) | 中身は nginx。Apache-2.0。v5.7.0 は Kubernetes 1.30〜1.37 でテスト済み | annotation が nginx.org/ 接頭辞の別仕様で、全 Ingress の書き換えが必要。Helm で自前導入・自前更新になる。一部機能は有償の NGINX Plus 限定 |
| 旧 ingress-nginx v1.15.1 を自前導入 | annotation がそのまま使える | 脆弱性が修正されない。1.36 は対象外 |
| 1.35 で止める | 書き換え不要 | 1.35 は 2027 年 2 月にサポートが終わる。先延ばしにしかならない |
| ホストに nginx を直接入れる | apt の nginx が TLS を終端し、NodePort へ転送する | 振り分け設定が Kubernetes の外に出る。サービスごとに NodePort を固定で割り当てて管理する必要がある |
F5 NGINX Ingress Controller の annotation は、ingress-nginx と次のように対応する (annotation 一覧)。
| ingress-nginx | F5 NGINX Ingress Controller |
|---|---|
proxy-body-size |
nginx.org/client-max-body-size |
proxy-read-timeout 等 |
nginx.org/proxy-read-timeout 等 |
proxy-buffer-size |
nginx.org/proxy-buffer-size |
server-snippet |
nginx.org/server-snippets (コントローラーに -enable-snippets が必要) |
rewrite-target (正規表現) |
nginx.org/rewrite-target + nginx.org/path-regex |
upstream-vhost |
nginx.org/upstream-vhost (変数は使えない) |
proxy-redirect-off |
直接の対応なし。proxy-redirect-from / -to で代用 |
今後の標準
ingress-nginx の後継として単一の標準コントローラーがあるわけではない。標準になるのは API のほうで、それが Gateway API である。Ingress API は機能追加が止まっており (廃止予定ではない)、新機能は Gateway API にだけ入る。Traefik、NGINX Gateway Fabric、Envoy Gateway、Istio、Cilium などが Gateway API を実装している。
軽量ディストリビューションの既定という意味では Traefik である。k3s も microk8s 1.35 以降も既定は Traefik になった。
F5 NGINX Ingress Controller は、nginx の挙動を維持したい場合の移行先としては有力である。ただし F5 が Gateway API 向けに出しているのは別製品の NGINX Gateway Fabric で、将来 Gateway API に移る時は製品を乗り換えることになる。Traefik なら同じコントローラーのまま Gateway API に移れる。
運用コストで比べると、ディストリビューションと一緒に更新される Traefik が有利である。以下は、同梱 Traefik を --disable=traefik で無効にして ingress-nginx を別途入れていた k3s を、Traefik に切り替える手順である。
k3s での移行手順
Kubernetes のアップグレード
k3s のアップグレードは、インストールスクリプトをチャネルを変えて再実行する。マイナーバージョンは 1 つずつ上げる。
curl -sfL https://get.k3s.io | INSTALL_K3S_CHANNEL=v1.34 \
INSTALL_K3S_EXEC="--disable=traefik --disable=servicelb" \
sh -s - --write-kubeconfig-mode 644
引数はインストール時と同じものを全部渡す。省略した引数は systemd の unit ファイルから消える。事前に /var/lib/rancher/k3s/server と /etc/rancher/k3s、k3s のバイナリを退避しておく。
ingress-nginx v1.13 の対応範囲は Kubernetes 1.33 までなので、1.34 に上げた時点で ingress を切り替える。
ingress-nginx の撤去
upstream の baremetal 用 manifest から入れた ingress-nginx は、namespace に入らないリソースを個別に消す。
kubectl delete validatingwebhookconfiguration ingress-nginx-admission
kubectl delete ns ingress-nginx
kubectl delete clusterrole ingress-nginx ingress-nginx-admission
kubectl delete clusterrolebinding ingress-nginx ingress-nginx-admission
kubectl delete ingressclass nginx
同梱 Traefik の有効化
k3s 1.34 に同梱されている Traefik の Helm chart は 40.1.5 (Traefik v3.7 系) である。前述のとおり、Traefik v3 の entrypoint の既定 readTimeout は 60 秒である。ingress-nginx で proxy-read-timeout: "1800" を指定していた長時間リクエストが切れないよう、HelmChartConfig で entrypoint のタイムアウトを延ばす。キーの位置は同梱 chart の values.yaml で確認できる。
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
web:
transport:
respondingTimeouts:
readTimeout: 1800s
writeTimeout: 1800s
websecure:
transport:
respondingTimeouts:
readTimeout: 1800s
writeTimeout: 1800s
このファイルを /var/lib/rancher/k3s/server/manifests/ に置くと、k3s が自動で適用する。その上で --disable=traefik --disable=servicelb を外して再インストールする。
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.34.12+k3s1 \
sh -s - --write-kubeconfig-mode 644
ベアメタルのロードバランサーが無くても、servicelb (klipper-lb) を有効にすると hostPort で 80/443 を受ける小さな Pod が起動し、Traefik の LoadBalancer Service にノードの IP が付く。
適用後、Traefik の起動引数に --entryPoints.websecure.transport.respondingTimeouts.readTimeout=1800s などが入っていることを確認できる。長時間リクエストでの動作は未検証である。
結果と注意点
- annotation を使っていない Ingress は、書き換えずに Traefik が処理する。TLS も Ingress が参照する既存の Secret の証明書がそのまま使われる
- Traefik の IngressClass は default として作られる。そのため
ingressClassNameの無い Ingress も Traefik が処理する。ingress-nginx の IngressClass が default 指定されていなかった環境では、それまで無視されていた class 未指定の Ingress が、切り替え後に有効になる - 同梱 Traefik の版は k3s 1.34〜1.36 で同じ (3.7.13) で、1.35、1.36 と上げても HelmChartConfig のタイムアウト設定は維持される
microk8s での移行の注意点
ingress-nginx 専用の annotation は、Traefik では次のように扱う。
| annotation | Traefik での扱い |
|---|---|
proxy-body-size |
Traefik は既定で上限が無いので不要 |
proxy-read-timeout 等 |
entrypoint のタイムアウト設定で吸収 |
server-snippet |
Middleware で書き直す |
rewrite-target (正規表現) |
ReplacePathRegex Middleware で書き直す |
upstream-vhost / proxy-redirect-off |
Headers Middleware で書き直す |
Traefik v3.5 以降には、ingress-nginx の annotation を解釈する互換 provider (kubernetesIngressNGINX) がある。どの annotation まで解釈するかは未検証である。
microk8s の公式手順は、マイナーバージョンを 1 つずつ snap refresh することである。
sudo snap refresh microk8s --channel=1.25/stable
microk8s status --wait-ready
addon と CNI (calico) は自動では更新されない。1.24 の頃に入れた calico は 3.21 系で Kubernetes 1.25 以降に対応していないため、途中で snap 同梱の manifest を当て直す必要がある。また、古い microk8s の args/kubelet には、kubelet 1.27 で削除された --container-runtime=remote が残っていることがある。snap revert で戻せるのは 1 段だけなので、事前に全リソースの YAML ダンプと microk8s dbctl backup を取っておく。
1.35 で ingress addon が Traefik に変わるので、作業は 2 段に分けるのがよい。
- ingress-nginx の addon のまま 1.34 まで上げる。API の削除 (1.25 の PodSecurityPolicy など) と calico の更新をここで片付ける
- Ingress の annotation を Traefik 向けに書き換えてから、1.35 → 1.36 に上げる
1.24 から 1.34 までは 10 段ある。1 段あたり refresh と確認で 10〜15 分かかるとすると、2〜3 時間の作業になる。
開発相談をお待ちしています。