KubernetesのSecretsは「金庫」ではない:etcdを覗き見られる前に知るべき現実
「KubernetesのSecretsは暗号化されているから大丈夫」。もしチームの誰かがそう言っていたら、即座に修正が必要です。
こんにちは。セキュリティチームのチーフエンジニアです。今日は、多くのエンジニアが陥る「K8s Secretsの幻想」と、それを現実的な脅威から守るための防御策について、現場の視点から解説します。
1. なぜ「デフォルト」のSecretsは無防備なのか
Kubernetesの Secret オブジェクトは、APIサーバー経由でアクセスするとBase64デコードされた状態で取得できます。しかし、これ自体は「転送時の保護」に過ぎません。
真の問題は、バックエンドである etcd にあります。
Kubernetesのクラスターデータストアである etcd は、デフォルト設定ではデータを暗号化せずにディスクへ保存します。つまり、何らかの理由でクラスターのノードに侵入を許したり、etcdのバックアップファイルがクラウドストレージ(S3バケットなど)に漏洩したりした瞬間、すべての機密情報は「平文」として攻撃者の手に渡ります。
攻撃者の視点:PoC(概念実証)
攻撃者がクラスター内で一時的なPod(kubectl exec等が可能)を確保できた場合、あるいは etcd への読み取り権限(あるいはバックアップへのアクセス権)を得た場合、以下のように情報を抽出します。
# etcdctlを使って直接データをダンプする(認証情報が漏れた想定)
ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
get /registry/secrets/default/db-secret --print-value-only
これだけで、Base64エンコードされた文字列が手に入ります。echo "BASE64文字列" | base64 -d と叩けば、DBのパスワードやAPIキーが丸見えです。
2. Encryption at Rest:KMSによる暗号化
この脅威を防ぐ唯一の正攻法が、Encryption at Rest(保存時の暗号化) です。これを有効にすると、Kubernetesは etcd に書き込む直前に、指定したKMS(AWS KMS, GCP KMS, Azure Key Vaultなど)を用いてデータを暗号化します。
実装:EncryptionConfiguration の設定
Kubernetes APIサーバーに以下の設定ファイル(encryption-config.yaml)を読み込ませる必要があります。
# encryption-config.yaml
kind: EncryptionConfiguration
apiVersion: apiserver.config.k8s.io/v1
resources:
- resources:
- secrets
providers:
# AWS KMSを使用する場合の例
- kms:
name: my-kms-provider
# AWS KMSのARNを指定
endpoint: unix:///var/run/kmsplugin/socket.sock
cachesize: 100
timeout: 3s
# 失敗時のフォールバック(推奨されませんが移行用)
- identity: {}
3. アプリケーションコード側での防御:Secretを「環境変数」にしない
インフラ側で暗号化しても、Pod内で環境変数として DB_PASSWORD を読み込む設計だと、プロセスの環境変数を覗き見られたり、ログに出力されたりするリスクが残ります。
最も堅牢なのは、「ボリュームマウント」し、権限を最小化したファイルとして読み込むことです。
Pythonでのセキュアな読み込みサンプル
環境変数に頼らず、マウントされたファイルから直接読み込む実装例です。
import os
def get_db_password():
# Kubernetesでマウントされたシークレットファイルのパス
secret_path = "/etc/secrets/db-password"
try:
with open(secret_path, "r") as f:
# 読み込み、末尾の改行を除去
return f.read().strip()
except FileNotFoundError:
# デバッグ用ログに機密情報を出さないよう注意
raise Exception("シークレットファイルが見つかりません")
# 利用時はメモリ上で扱う(ログ出力は厳禁)
db_password = get_db_password()
4. 現場で意識すべきセキュリティの鉄則
最後に、インシデントハンドリングの経験から、必ず守ってほしい「3つのルール」を伝えます。
1. etcdバックアップの暗号化を疑え: クラスターのバックアップをS3に置いている場合、そのバケット自体に暗号化設定(SSE-KMSなど)が適用されているか、今すぐ確認してください。
2. RBACの監査: get secrets 権限を持つサービスアカウントが多すぎませんか?「最小権限の原則」を適用し、本当にシークレットが必要なPodにのみ権限を与えてください。
3. Secret Store CSI Driverの導入: クラウドネイティブな運用なら、Secret Store CSI Driver を検討してください。これを使えば、K8sのSecretオブジェクトを介さず、直接クラウドのKMSから値をPodにマウントできるため、etcdのリスクを根本から回避できます。
セキュリティは「設定して終わり」ではなく、常に「どこが突破口になるか」を疑い続けるプロセスです。今日紹介した設定を、今週末の運用でぜひ適用してみてください。何かあれば、いつでもコードレビューを依頼してください。一緒に堅牢なシステムを築きましょう。
コメント