おい、ちょっと手を止めてこっちを向いてくれ。
Kubernetesクラスターの構築、お疲れ様。サクッとマニフェストを流し込んで、Podがモリモリ立ち上がると「よし、動いた!」って達成感があるよな。でも、ちょっと待ってほしい。その下回り、本当に「ハッカーの侵入を許さない要塞」になっているか?
現場でいくつものインシデントハンドリングをやっていると、開発者が一番やらかしやすい盲点に気づく。それが 「APIサーバーの通信暗号化とTLS設定の甘さ」 だ。
Kubernetesの心臓部である kube-apiserver は、クラスター内のすべての通信が集中する最大の要所だ。ここを踏み破られたら、コンテナのコンフィグも、シークレット(DBのパスワードやAPIキー)も、すべてが攻撃者の手中に落ちる。今回は、甘いTLS設定が招くリスクと、それを実務で完全に封じ込めるための具体的な設定を叩き込んでいく。
—
1. 攻撃者が狙う「甘いTLS設定」の現実
「うちは社内ネットワーク内だから」「HTTPS化してあるから大丈夫」……そんな言い訳を聞くたびに、私の頭痛の種が増える。
攻撃者は、perimeter(境界型防御)の内側に侵入した瞬間、あるいはミスコンフィグによって外部に露出した kube-apiserver に対して、以下のような手法で牙を剥く。
脆弱な暗号スイート(Cipher Suites)の悪用
古いTLSバージョン(TLS 1.0/1.1)や、脆弱性のある暗号スイート(CBCモードやRC4など)が有効になっていると、通信の盗聴(Sniffing)や中間者攻撃(MitM)の餌食になる。特に、総当たりやダウングレード攻撃によってセッションキーが暴かれ、管理者のトークンが抜かれるインシデントは後を絶たない。
認証バイパスと不十分なクライアント証明書検証
「とりあえず通信できればいいや」と、--insecure-port を有効にしていたり、クライアント証明書の検証を厳密に行っていない環境を見たことがあるか? これらは「玄関の鍵を開けっぱなしにして、犬のぬいぐるみだけ置いてある」ような状態だ。誰でも curl 一発でAPIサーバーを叩き、クラスターの全権限を奪うことができる。
—
2. 【実務設計】APIサーバーを鉄壁にする設定ファイル
口酸っぱく言っているだけではエンジニアの時間は守れない。ここからは、明日の朝一番で君たちのクラスターに適用すべき、具体的な kube-apiserver の設定(静的Podマニフェスト)を公開しよう。
kube-apiserver.yaml のセキュア設定サンプル
以下の設定では、TLS 1.2および1.3のみを強制し、安全性に定評のある強力な暗号スイートだけを厳選して許可している。さらに、不安全なポート(--insecure-port)は完全に無効化(0)し、すべての通信に強力なクライアント証明書認証を義務付けている。
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
labels:
component: kube-apiserver
tier: control-plane
spec:
containers:
- name: kube-apiserver
image: k8s.gcr.io/kube-apiserver:v1.28.0
command:
- kube-apiserver
# --- 認証・認可の基本設定 ---
- --authorization-mode=Node,RBAC
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
# --- セキュリティの要:暗号化とTLS設定 ---
# 不安全な非暗号化ポートを完全に閉塞(0を指定)
- --insecure-port=0
# 許可する最小のTLSバージョンを 1.2 に設定(古いプロトコルを排除)
- --tls-min-version=VersionTLS12
# 強力な暗号スイート(Cipher Suites)の明示的指定
# AEAD(GCMやChaCha20)を採用し、脆弱なCBCモードやRC4を排除
- --tls-cipher-suites=
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
TLS_CHACHA20_POLY1305_SHA256
volumeMounts:
- mountPath: /etc/kubernetes/pki
name: k8s-certs
readOnly: true
volumes:
- hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
name: k8s-certs
—
3. クライアント側の実装と接続検証(Pythonスクリプト例)
APIサーバー側のTLSとクライアント証明書を厳格化したら、当然ながらそこにアクセスするアプリケーションや管理スクリプト側も、正しい証明書とTLS設定で行う必要がある。
「とりあえず verify=False にしておけば動くっしょ」なんてコードを書く奴がいたら、私の権限で即座にPRをマージ拒否するからそのつもりでいてくれ。
以下は、厳格なTLS環境下にあるKubernetes APIサーバーに対して、Pythonの requests ライブラリを用いて安全にリクエストを送信するサンプルコードだ。
import requests
from requests.exceptions import SSLError
# APIサーバーのエンドポイント(内部FQDNまたはIP)
API_SERVER_URL = "https://kubernetes.default.svc:443/api/v1/namespaces"
# クライアント証明書と秘密鍵のパス(mTLS用)
CLIENT_CERT = ("/etc/kubernetes/pki/apiserver-client.crt", "/etc/kubernetes/pki/apiserver-client.key")
# クラスターのルートCA証明書のパス(自己署名証明書の場合は必須)
CA_BUNDLE = "/etc/kubernetes/pki/ca.crt"
def fetch_kubernetes_namespaces():
try:
# verify引数にCA証明書のパスを指定し、中間者攻撃を確実に防止する
# cert引数でクライアント証明書を渡し、mTLS(相互認証)を確立する
response = requests.get(
API_SERVER_URL,
cert=CLIENT_CERT,
verify=CA_BUNDLE,
timeout=10
)
# ステータスコードのチェック
response.raise_for_status()
print("[+] APIサーバーへの接続に成功しました。")
namespaces = response.json()
for ns in namespaces.get("items", []):
print(f" - Namespace: {ns['metadata']['name']}")
except SSLError as e:
print(f"[-] TLSハンドシェイクまたは証明書検証に失敗しました: {e}")
except requests.exceptions.RequestException as e:
print(f"[-] 通信エラーが発生しました: {e}")
if __name__ == "__main__":
fetch_kubernetes_namespaces()
—
4. チーフからの実践アドバイス:導入後のチェックリスト
設定ファイルをデプロイしたら、「よし完了」ではない。ホワイトハッカーの視点で、本当に意図した通りに要塞化されているかを自分の手でテストしろ。
1. 外部からのスキャン確認
社外の踏み台や検証端末から、nmapや openssl s_client を使って古いプロトコル(TLS 1.0/1.1)で接続を試みること。
openssl s_client -connect <API_SERVER_IP>:6443 -tls1
これが handshake failure で弾かれることを確認するまでが仕事だ。
2. 認証なしアクセスの検証
クライアント証明書なしで curl を叩き、HTTPステータスコード 401 Unauthorized または 403 Forbidden が返ってくることを必ずログとあわせて確認しろ。
セキュリティは「面倒くさい手続き」ではなく、「システムの寿命を延ばす保険」だ。今日のインフラ設定の妥協が、明日の深夜のインシデント対応を生む。頼むから、こういう基礎の基礎を徹底してくれ。期待しているぞ。
コメント