containerd TLS:信頼チェーンと一時的な検証スキップの判断
技術ノート
公開 / DavidHLPL
本ページは、プライベートレジストリで x509 の pull エラーが出たとき、ノードと containerd に CA を信頼させるべきか、それとも原因切り分けの間だけ検証をスキップするべきかを答える。containerd の設定、ノード OS の信頼ストア、Kubernetes の Secret/ServiceAccount、キャッシュを分離し、異なる層の失敗を混同しないようにする。
コアメカニズム
1. pull 経路と責任境界
Pod → kubelet → imagePullSecrets/ServiceAccount → CRI → containerd
→ config.toml の config_path → certs.d/<registry>/hosts.toml
→ Registry TLS → manifest/layer
| 観測結果 | 最初に見る層 | 再利用できる判断 |
|---|---|---|
x509: certificate signed by unknown authority |
Registry TLS / containerd | 証明書チェーン、SAN、config_path、ノード上の ca.crt を確認する。 |
certificate is valid for xxx, not yyy |
Registry アドレス | イメージアドレスを証明書 SAN に合わせ、対象外の IP に置き換えない。 |
TLS は通るが unauthorized |
Kubernetes 認証情報 | Pod の imagePullSecrets と、明示しない場合に継承する ServiceAccount を確認する。 |
crictl pull は成功するが Pod は失敗 |
Kubernetes またはキャッシュ | CA を変更する前に Secret、ServiceAccount、namespace、イメージ名、古いレイヤーを見る。 |
2. TLS の二つの選択肢
| 選択 | 最小設定 | 判断 | 代償 |
|---|---|---|---|
| 信頼 CA(本番経路) | hosts.toml に ca = "ca.crt" |
プライベートレジストリを長期運用し、ノードがサーバーを認証する必要がある | pull を行うすべての Worker に証明書と設定を配布する必要がある。 |
| 一時的な検証スキップ | skip_verify = true |
テスト、デモ、一時的な内網レジストリで、証明書検証が原因かを確認する | 証明書の出所を検証せず、中間者攻撃のリスクがある。本番の既定値にはしない。 |
skip_verify が変えるのは TLS 検証だけである。誤ったホスト名、ポート、認証情報、DNS、プロキシ経路は直らない。本番設定の最小例は次のとおり。
server = "https://harbor.example.com"
[host."https://harbor.example.com"]
capabilities = ["pull", "resolve", "push"]
ca = "ca.crt"
一時診断では最後の設定だけを skip_verify = true に置き換える。ポート付きなら harbor.example.com:8443 を Registry アドレスと certs.d ディレクトリ名の両方に含める。
3. containerd、ノード CA、Kubernetes 認証情報、キャッシュは別物
- containerd 層:新しい設定では
/etc/containerd/certs.d配下のhosts.tomlを読む。raw の例では containerd 1.x はversion = 2とio.containerd.grpc.v1.cri、2.x はversion = 3とio.containerd.cri.v1.imagesを使う。バージョン依存なのでcontainerd --versionで確認する。 - ノード OS の CA 層:
ca.crtを Debian/Ubuntu、RHEL 系、Arch の信頼ディレクトリに置くと、主にcurl、openssl、その他のシステムサービスが信頼できるようになる。containerd のconfig_pathとhosts.tomlの代わりにはならない。 - Kubernetes 認証情報層:
imagePullSecretsまたは ServiceAccount は Registry 認証を解決する。TLS 通過後もunauthorizedなら、TLS ではなく正しいdocker-registrySecret の再作成・バインドを行う。 - キャッシュ層:ノード上の失敗イメージや古いレイヤーにより、直接 pull と Pod の結果が食い違って見えることがある。キャッシュ削除は検証手段であり、信頼チェーンの修正ではない。
適用条件
- 本番レジストリでは信頼 CA を使い、実際に pull するすべての Worker で
hosts.toml、ca.crt、config.tomlを揃える。 skip_verifyはテストやデモの切り分けだけに使い、一時設定であることを記録して、確認後はca = "ca.crt"に戻す。- ポート付き Registry のパスを正確に保つ。例は
/etc/containerd/certs.d/harbor.example.com:8443/である。 crictl pull成功後に Kubernetes 層を判断する。失敗したら TLS、CA、hosts、DNS、プロキシ、ネットワークへ戻る。- 新しいリリースでは古い
registry.configsの例よりcerts.d/hosts.tomlを優先する。ただし旧形式の互換性は未確認のバージョンに依存する。
適用外とリスク
skip_verify = trueを本番クラスタに残さない。証明書の出所を認証せずにサーバーを受け入れる。- 「OS の CA を更新した」ことを「containerd が読み込んだ」ことと同一視しない。正しい
config_pathを確認し、サービスを再起動する。 unauthorizedが出たからといって CA を何度も交換しない。これは Secret、ServiceAccount、Registry アカウントの境界である。/root/.docker/config.jsonや/var/lib/kubelet/config.jsonを確認なしに削除しない。raw はそれらを過去の残留候補として挙げているだけである。- 出典の
EXPLAIN例と同様に、containerd 1.x/2.xの plugin path・CA 更新コマンドも版・platform 条件付きで、未確認環境へ外挿しない。
最小検証
層を区別できる検査だけを順に実行する。
containerd --version
sudo systemctl status containerd --no-pager
sudo crictl pull harbor.example.com/project/app:v1
crictl pullがx509ならhosts.toml、CA、SAN、ポートディレクトリを再確認する。ログはsudo journalctl -u containerd -n 200 --no-pagerで見る。- 認証エラーなら Pod の ServiceAccount と Secret を見る。
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.serviceAccountName}'
kubectl get sa <service-account> -n <namespace> -o yaml
- CA の subject、issuer、日付を確認する。
openssl x509 -in /etc/containerd/certs.d/harbor.example.com/ca.crt -noout -subject -issuer -dates
crictl pullは成功するのに Pod が失敗するなら、kubectl describe podの Events を確認し、必要な場合だけcrictl images/crictl rmiで古いキャッシュを除外する。
証拠と不確実性
- 出典事実:
legacy-containerd-tls-troubleshootingは x509/SAN/ポート/認証情報/キャッシュの症状、containerd 1.x/2.x の例、certs.dの二つの TLS 設定、ServiceAccount/Secret の確認、crictl pullの分岐を記録している。 - 本ページの統合:それらを「失敗層を分類してから CA または一時スキップを選ぶ」決定表に圧縮した。「OS CA は containerd 設定ではない」はその経路から導いた境界である。
- 未確認:現在のクラスタの containerd の正確なバージョン、Registry CA の完全性、証明書 SAN、ノードの proxy/NO_PROXY、Secret のバインド、キャッシュ状態は実環境で確認する必要がある。
関連ページ
出典と関連文書
研究記録
- 元の文書: src/content/note/ja/containerd-tls-troubleshooting.md
- 出典リビジョン: f49953fb0d4bd52a39bf81167b0c4b7dd7d78a64
- 証拠の状態: 有効