KubernetesにおけるBitnami Sealed Secrets導入ガイド:安全なGitOpsシークレット管理

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Quick start: 5分で最初のシークレットを暗号化する

百聞は一見に如かず。4つのシンプルなステップで、実際にシークレットを暗号化してクラスターへ適用してみましょう。

ステップ 1: Sealed Secrets Controllerのインストール

コントローラーはクラスター内でバックグラウンド実行され、復号処理を担当します。以下の2つのコマンドでv0.24.5をデプロイします。

kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.5/controller.yaml
kubectl rollout status deployment sealed-secrets-controller -n kube-system

10〜20秒ほど待ちます。PodがRunning状態になると、コントローラーは初回用の4096-bit RSAキーペアを自動生成します。

ステップ 2: ローカル環境へのkubeseal CLIのインストール

kubesealはクライアント側のツールです。コードをコミットする前にシークレットを暗号化することが唯一の役割です。

Linuxの場合:

wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.5/kubeseal-0.24.5-linux-amd64.tar.gz
tar -xvzf kubeseal-0.24.5-linux-amd64.tar.gz
sudo install -m 755 kubeseal /usr/local/bin/kubeseal

macOSの場合は、brew install kubesealを実行するだけです。

ステップ 3: シークレットの作成と暗号化(Seal)

例として、ユーザー名と16文字のパスワードを含むPostgreSQLの認証情報を作成してみましょう。

# 1. dry-runモードで未暗号化のシークレットマニフェストを作成
kubectl create secret generic db-credentials \
  --from-literal=username=postgres \
  --from-literal=password='kX9#mP2$vL8@qR5!' \
  --dry-run=client -o yaml > secret-raw.yaml

# 2. kubesealを使用してSealedSecretへ暗号化
kubeseal -f secret-raw.yaml -o yaml > sealedsecret.yaml

# 3. 誤コミットを防ぐため、元のrawファイルを即座に削除
rm -f secret-raw.yaml

ステップ 4: クラスターへの適用と動作検証

暗号化されたファイルをクラスターに適用します。

kubectl apply -f sealedsecret.yaml

# コントローラーによって生成された通常のSecretを確認
kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d

復号されたパスワードが元の値と完全に一致することが確認できます。これでsealedsecret.yamlはGitHubやGitLabへ安全にプッシュできるようになりました。あわせてCI/CDパイプラインのシークレット管理も見直すことで、リポジトリ全体のセキュリティをより強固に保てます。

問題の本質:標準のKubernetes Secretはなぜ脆弱なのか?

Kubernetesセキュリティの初学者の多くは、Secretがセキュアであると誤解しがちです。しかし、現実は異なります。

Kubernetes Secretのデータは、単にBase64でエンコードされているに過ぎません。Base64はバイナリデータを文字列に変換するためのフォーマット変換であり、暗号化やセキュリティ保護の機能はありません。マニフェストファイルを開けば、誰でも1秒以内に平文へデコードできてしまいます。このようなリスクを排除するには、Kyvernoによるセキュリティ自動化でマニフェストの適用ポリシーを厳格化するのも効果的です。

GitOpsが抱える難題

GitOpsを採用する場合、すべてのマニフェストをGitリポジトリで管理する必要があります。Gitこそがシステム全体の状態に対する「信頼できる唯一の情報源(Single Source of Truth)」となるためです。

ここで大きなジレンマが生じます。平文のシークレットをGitにコミットするのは極めて危険です。一方で、クラスター外でシークレットを手動設定すると、GitOpsの一貫性が崩れてしまいます。HashiCorp Vaultの導入を選択するチームも多いですが、Vaultは強力である反面、リソース消費量が多く運用も複雑なため、中小規模のシステムではオーバーヘッドが大きくなりがちです。

Sealed Secretsによるアプローチ

Bitnami Sealed Secretsは、非対称暗号(公開鍵暗号方式)を採用し、明確な役割分担を実現しています。

  • Public Key(公開鍵): コントローラーが自動生成し、すべての開発者に公開されます。この鍵をローカルに取得してシークレットをカスタムリソースSealedSecretに暗号化します。この鍵は「施錠」専用であり、逆方向に復号することはできません。
  • Private Key(秘密鍵): kube-system名前空間内に安全に保管され、コントローラーのみがアクセス権限限を持ちます。Git経由でSealedSecretがデプロイされると、コントローラーがそれを検知して自動復号し、Podが利用可能なネイティブのK8s Secretを生成します。

万が一Gitリポジトリ全体が攻撃者に漏洩しても、暗号化された無意味な文字列(暗号文)しか見えません。

実践運用:スコープ制御と秘密鍵のバックアップ戦略

1. スコープ(Scope)による暗号化制御

デフォルトでは、kubesealはstrictスコープを使用します。これは、シークレットが最初に指定されたリソース名と名前空間に厳密にバインドされることを意味します。仮にYAMLファイル内の名前空間が改ざんされた場合、コントローラーは即座に復号を拒否します。

設計要件に応じて、以下の3つのスコープから選択できます。

  • Strict(デフォルト): シークレット名と名前空間の完全一致を要求します。本番環境(プロダクション)に最適です。
  • Namespace-wide: 同一名前空間へのデプロイであれば、シークレット名の変更を許可します:
    kubeseal --scope namespace-wide -f secret-raw.yaml -o yaml > sealedsecret.yaml
  • Cluster-wide: クラスター内のあらゆる名前空間で復号を許可します。Docker Registryの共通認証情報などに適しています:
    kubeseal --scope cluster-wide -f secret-raw.yaml -o yaml > sealedsecret.yaml

2. ディザスタリカバリ計画:秘密鍵を絶対に失わないために

秘密鍵の喪失は、すべてのシークレットの喪失を意味します。クラスター障害が発生してゼロから再構築する場合、Git上にある何百ものSealedSecretファイルを二度と復号できなくなってしまいます。

インストール直後に、必ずコントローラーの鍵をバックアップしてください。

kubectl get secret -n kube-system \
  -l sealedsecrets.bitnami.com/sealed-secrets-key \
  -o yaml > master-sealed-secrets-key.yaml

このバックアップファイルをチームのパスワード管理ツール(1PasswordやBitwarden Vaultなど)に安全に保管します。クラスター復旧時は、先にこのシークレットを適用するだけで済みます。

kubectl apply -f master-sealed-secrets-key.yaml
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.5/controller.yaml

コントローラーが既存の鍵を自動認識し、Git上の全データを通常通り復号します。ファイルを再暗号化する必要は一切ありません。

本番運用における3つの重要ポイント

  • 鍵のローテーション(Key Rotation)の把握: デフォルトでは30日ごとに新しいキーペアが自動生成されます。過去の鍵も保持されるため既存のシークレットは引き続き復号可能ですが、ローテーションが行われるたびにバックアップスクリプトを再実行し、有効な秘密鍵をすべて網羅しておくことが推奨されます。
  • Gitleaksによるシークレット漏洩防止: gitleaksやtrufflehogをpre-commit hookに導入します。開発者が誤って未暗号化のsecret-raw.yamlをリモートリポジトリへコミットする事故を未然に防止できます。
  • ArgoCD / FluxCDとの統合: SealedSecretは標準的なKubernetes CRDです。ArgoCDは追加プラグインなしでネイティブに検知・同期します。Sealed Secretsコントローラーとのリソース所有権の競合を防ぐため、生成される通常のSecretを同期対象外(ignore)に設定しておくだけで問題ありません。
Share: