Kubernetes Secret の暗号化:デフォルトとカスタマイズの詳細ガイド
Kubernetes (k8s) は、コンテナ化されたアプリケーションのデプロイ、スケーリング、および管理を自動化するための強力なオープンソースプラットフォームです。アプリケーションをKubernetes上で実行する際、パスワード、APIキー、証明書などの機密情報を安全に管理することが非常に重要になります。Kubernetes は、これらの機密情報をSecretオブジェクトとして管理するためのメカニズムを提供しています。
Kubernetes Secretは、デフォルトではbase64エンコードされた状態でetcdに保存されます。しかし、これは暗号化ではありません。etcdへのアクセス権を持つ者は誰でもSecretの内容を簡単にデコードできてしまいます。そのため、より高いセキュリティを確保するためには、Kubernetes Secretを暗号化することが推奨されます。
本記事では、Kubernetes Secretの暗号化におけるデフォルトの動作と、カスタマイズされた暗号化戦略の実装について深く掘り下げていきます。以下の内容を網羅的に解説します。
目次
- Kubernetes Secret の基礎
- 1.1 Secret の定義と役割
- 1.2 Secret の種類
- 1.3 Secret の作成と管理
- 1.4 Secret の利用方法
- デフォルトの Secret 保存とセキュリティ上の懸念
- 2.1 etcd における Secret の保存形式
- 2.2 デフォルト設定におけるセキュリティリスク
- etcd 暗号化の有効化:Kubernetes デフォルトの暗号化
- 3.1 暗号化プロバイダの選択
- 3.2 暗号化キーの生成と管理
- 3.3 kube-apiserver の設定
- 3.4 etcd の暗号化設定
- 3.5 暗号化の検証
- 3.6 ローテーション戦略とメンテナンス
- カスタマイズされた Secret 暗号化戦略
- 4.1 HashiCorp Vault を利用した Secret 管理
- 4.2 AWS KMS を利用した Secret 管理
- 4.3 Google Cloud KMS を利用した Secret 管理
- 4.4 Azure Key Vault を利用した Secret 管理
- 4.5 外部 Secret ストア連携のメリットとデメリット
- Secret 暗号化におけるベストプラクティス
- 5.1 最小権限の原則の適用
- 5.2 Secret のローテーション
- 5.3 アクセスログの監視
- 5.4 定期的な監査
- 5.5 Secret の適切なスコープ
- まとめ:安全な Kubernetes Secret 管理に向けて
1. Kubernetes Secret の基礎
1.1 Secret の定義と役割
Kubernetes Secret は、パスワード、OAuth トークン、SSH キーなどの機密情報を保存および管理するための Kubernetes オブジェクトです。Secret を利用することで、機密情報をアプリケーションのコードやコンテナイメージに直接ハードコードすることを避け、より安全な方法で機密情報を管理できます。
Secret は、ConfigMap と同様にキーと値のペアを保持しますが、ConfigMap は機密情報ではない設定データを扱うことを意図しているのに対し、Secret は機密情報を扱うことを意図している点が異なります。
1.2 Secret の種類
Kubernetes には、いくつかの組み込みの Secret タイプがあります。
- Opaque: 最も一般的なタイプで、任意のバイナリデータを格納できます。base64エンコードされたキーと値のペアとして保存されます。
- kubernetes.io/tls: TLS 証明書とキーを格納するために使用されます。
tls.crtキーに証明書、tls.keyキーに秘密鍵を格納します。 - kubernetes.io/dockerconfigjson: Docker レジストリ認証情報を格納するために使用されます。
dockercfgキーに Docker config.json ファイルを格納します。 - kubernetes.io/service-account-token: サービスアカウントのトークンを格納するために使用されます。Kubernetes が自動的に作成し、Pod に注入します。
1.3 Secret の作成と管理
Secret は、kubectl コマンドラインツールまたは YAML ファイルを使用して作成できます。
kubectl コマンドによる作成例:
bash
kubectl create secret generic my-secret \
--from-literal=username=myuser \
--from-literal=password=mypassword
このコマンドは、my-secret という名前の Opaque Secret を作成し、username と password という2つのキーと値のペアを格納します。
YAML ファイルによる作成例:
yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
username: bXl1c2Vy
password: bXlwYXNzd29yZA==
この YAML ファイルも、my-secret という名前の Opaque Secret を作成しますが、値は base64 エンコードされていることに注意してください。
Secret は、kubectl get secret <secret-name> コマンドで確認できます。 Secret の内容は、kubectl describe secret <secret-name> コマンドで確認できますが、値は base64 エンコードされたまま表示されます。デコードするには、kubectl get secret <secret-name> -o yaml コマンドで YAML 形式で出力し、base64 デコードツールを使用して値をデコードする必要があります。
Secret の更新は、kubectl edit secret <secret-name> コマンドで行うことができます。変更を適用すると、Kubernetes は Secret を更新し、関連する Pod に変更を反映させます (ただし、自動的に反映されない場合もあるので、Pod の再起動が必要になる場合があります)。
1.4 Secret の利用方法
Secret は、以下の方法で Pod で利用できます。
- 環境変数: Secret の値を環境変数として Pod に注入できます。
- ボリューム: Secret をボリュームとして Pod にマウントできます。
- イメージプルシークレット: プライベート Docker レジストリからイメージをプルするために使用されます。
環境変数による利用例:
yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: my-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: password
この例では、DB_USERNAME と DB_PASSWORD という2つの環境変数が Pod に設定され、それぞれ my-secret Secret の username と password の値が注入されます。
ボリュームによる利用例:
yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: my-secret
この例では、my-secret Secret が /etc/secrets ディレクトリにボリュームとしてマウントされます。コンテナは、このディレクトリ内のファイルとして Secret の値にアクセスできます。例えば、username の値は /etc/secrets/username ファイルから読み取ることができます。
2. デフォルトの Secret 保存とセキュリティ上の懸念
2.1 etcd における Secret の保存形式
デフォルトでは、Kubernetes Secret は etcd に base64 エンコードされた形式で保存されます。 etcd は、Kubernetes クラスタの状態を保存するための分散型キーバリューストアであり、クラスタの「脳」とも呼ばれます。
base64 エンコーディングは暗号化ではありません。単にバイナリデータをテキスト形式に変換するだけの技術であり、誰でも簡単にデコードできます。
2.2 デフォルト設定におけるセキュリティリスク
デフォルト設定では、以下のセキュリティリスクが存在します。
- etcd へのアクセス権を持つ者による Secret の漏洩: etcd への読み取りアクセス権を持つ者は誰でも、Secret の内容をデコードして機密情報を取得できます。
- etcd バックアップからの Secret の漏洩: etcd のバックアップファイルにも Secret が含まれるため、バックアップファイルへのアクセス権を持つ者も Secret を取得できます。
- etcd への侵入による Secret の漏洩: 攻撃者が etcd に侵入した場合、すべての Secret が漏洩する可能性があります。
これらのリスクを軽減するためには、Kubernetes Secret を暗号化することが非常に重要になります。
3. etcd 暗号化の有効化:Kubernetes デフォルトの暗号化
Kubernetes は、etcd に保存される Secret を暗号化するための組み込みのメカニズムを提供しています。このメカニズムを使用すると、Secret は暗号化された状態で etcd に保存され、セキュリティが向上します。
3.1 暗号化プロバイダの選択
Kubernetes は、以下の暗号化プロバイダをサポートしています。
- aescbc: AES-CBC 暗号化を使用します。
- kms: Key Management Service (KMS) を使用して暗号化キーを管理します。
- secretbox: NaCl SecretBox 暗号化を使用します。
一般的に、aescbc が最も単純で広く使用されているオプションです。KMS プロバイダは、より高度なセキュリティを提供しますが、追加の設定とインフラストラクチャが必要になります。secretbox は比較的新しいオプションであり、AES-CBC と同様の性能を提供しますが、NaCl ライブラリに依存します。
ここでは、最も一般的な aescbc プロバイダを使用した暗号化の設定について説明します。
3.2 暗号化キーの生成と管理
aescbc プロバイダを使用する場合、暗号化キーを生成する必要があります。キーは 32 バイト (256 ビット) のランダムなデータである必要があります。
以下のコマンドを使用して、ランダムなキーを生成できます。
bash
head -c 32 /dev/urandom | base64
生成されたキーは安全な場所に保存する必要があります。ローテーションの計画を立てることも重要です。定期的にキーをローテーションすることで、キーが漏洩した場合のリスクを軽減できます。
3.3 kube-apiserver の設定
暗号化を有効にするには、kube-apiserver の設定ファイルを変更する必要があります。設定ファイルは、Kubernetes クラスタの構成方法によって異なりますが、通常は /etc/kubernetes/manifests/kube-apiserver.yaml にあります。
設定ファイルを開き、spec.containers[0].command セクションに以下の引数を追加します。
yaml
- --encryption-provider-config=/etc/kubernetes/encryption-config.yaml
これは、kube-apiserver に暗号化プロバイダの設定ファイル (/etc/kubernetes/encryption-config.yaml) を使用するように指示します。
3.4 etcd の暗号化設定
次に、暗号化プロバイダの設定ファイルを作成する必要があります。ファイルの内容は以下のようになります。
yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <generated-key>
- identity: {}
このファイルは、secrets リソースを aescbc プロバイダで暗号化するように設定します。<generated-key> は、先ほど生成したキーに置き換えてください。
identity プロバイダは、暗号化に失敗した場合に使用されるフォールバックプロバイダです。これにより、暗号化が一時的に利用できない場合でも、Kubernetes が機能し続けることが保証されます。
このファイルを /etc/kubernetes/encryption-config.yaml に保存します。
3.5 暗号化の検証
設定を適用するには、kube-apiserver を再起動する必要があります。
bash
kubectl delete pod -n kube-system -l component=kube-apiserver
kube-apiserver が再起動したら、暗号化が正しく設定されていることを確認する必要があります。これを確認するには、新しい Secret を作成し、etcd に保存されている形式を確認します。
bash
kubectl create secret generic my-secret --from-literal=mykey=myvalue
kubectl get secret my-secret -o yaml | grep -i myvalue
もし、myvalue が base64 エンコードされた形式で表示された場合、暗号化はまだ有効になっていません。 kube-apiserver のログを確認して、エラーがないか確認してください。
暗号化が有効になると、etcd に保存されている Secret は、人間が読める形式ではなくなります。
既存の Secret を暗号化するには、それらを更新する必要があります。
bash
kubectl get secrets --all-namespaces -o json | jq '.items[].metadata | {name, namespace}' | while read item; do
name=$(echo $item | jq -r .name)
namespace=$(echo $item | jq -r .namespace)
kubectl patch secret -n $namespace $name -p '{"metadata":{"annotations":{"kubectl.kubernetes.io/restarted-at":"'$(date +%s)'"}}}' --type=merge
done
このスクリプトは、すべての Secret を反復処理し、kubectl patch コマンドを使用して、metadata.annotations に kubectl.kubernetes.io/restarted-at アノテーションを追加します。これにより、Secret が更新され、新しい暗号化形式で保存されます。
3.6 ローテーション戦略とメンテナンス
暗号化キーのローテーションは、セキュリティを維持するために不可欠です。キーが漏洩した場合、ローテーションによって影響範囲を限定できます。
Kubernetes では、aescbc プロバイダを使用する場合、複数のキーを EncryptionConfiguration ファイルに指定できます。
yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key2
secret: <new-generated-key>
- name: key1
secret: <old-generated-key>
- identity: {}
この例では、key2 が新しいキーとして追加され、key1 が古いキーとして残されています。 kube-apiserver は、新しい Secret を key2 で暗号化し、古い Secret を key1 で復号化します。
すべての Secret が新しいキーで暗号化されたら、古いキーを EncryptionConfiguration ファイルから削除できます。
キーのローテーションは、計画的に実行し、適切なテストを行うことが重要です。キーのローテーション中に問題が発生した場合、アプリケーションが利用できなくなる可能性があります。
4. カスタマイズされた Secret 暗号化戦略
Kubernetes のデフォルトの暗号化は、基本的なセキュリティを提供しますが、より高度なセキュリティ要件を満たすためには、カスタマイズされた暗号化戦略を検討する必要があります。
カスタマイズされた暗号化戦略では、外部の Secret ストア (HashiCorp Vault、AWS KMS、Google Cloud KMS、Azure Key Vault など) を利用して、Secret を管理および暗号化します。
4.1 HashiCorp Vault を利用した Secret 管理
HashiCorp Vault は、Secret を安全に保存、アクセス、および配布するためのツールです。 Vault を使用すると、Secret を動的に生成し、アクセス制御ポリシーを適用し、監査ログを記録できます。
Vault と Kubernetes を統合する方法はいくつかあります。
- Vault Agent Injector: Vault Agent Injector は、Kubernetes Mutating Admission Webhook を使用して、Pod の作成時に Vault Agent コンテナを自動的に挿入します。 Vault Agent は、Vault から Secret を取得し、それを共有ボリュームにマウントします。
- Vault Kubernetes Authentication: Vault Kubernetes Authentication は、Kubernetes サービスアカウントを使用して Vault で認証します。これにより、Pod は Vault で認証され、Secret にアクセスできます。
- kubectl Vault Plugin: kubectl Vault Plugin は、kubectl コマンドラインツールを使用して Vault から Secret を取得し、Kubernetes Secret として作成します。
4.2 AWS KMS を利用した Secret 管理
AWS Key Management Service (KMS) は、AWS 上で暗号化キーを管理するためのマネージドサービスです。 KMS を使用すると、暗号化キーを安全に保存し、アクセス制御ポリシーを適用し、監査ログを記録できます。
AWS KMS と Kubernetes を統合する方法はいくつかあります。
- KMS Provider for Kubernetes: KMS Provider for Kubernetes は、Kubernetes の組み込みの暗号化メカニズムを使用して、AWS KMS で Secret を暗号化します。
- AWS Secrets Manager: AWS Secrets Manager は、AWS 上で Secret を管理するためのマネージドサービスです。 Secrets Manager を使用すると、Secret を安全に保存し、アクセス制御ポリシーを適用し、監査ログを記録できます。 Secrets Manager を Kubernetes と統合するには、AWS Secrets and Configuration Provider (ASCP) を使用します。
4.3 Google Cloud KMS を利用した Secret 管理
Google Cloud Key Management Service (KMS) は、Google Cloud 上で暗号化キーを管理するためのマネージドサービスです。 KMS を使用すると、暗号化キーを安全に保存し、アクセス制御ポリシーを適用し、監査ログを記録できます。
Google Cloud KMS と Kubernetes を統合する方法はいくつかあります。
- KMS Provider for Kubernetes: KMS Provider for Kubernetes は、Kubernetes の組み込みの暗号化メカニズムを使用して、Google Cloud KMS で Secret を暗号化します。
- Google Cloud Secret Manager: Google Cloud Secret Manager は、Google Cloud 上で Secret を管理するためのマネージドサービスです。 Secret Manager を使用すると、Secret を安全に保存し、アクセス制御ポリシーを適用し、監査ログを記録できます。 Secret Manager を Kubernetes と統合するには、Google Cloud Secret Manager Operator を使用します。
4.4 Azure Key Vault を利用した Secret 管理
Azure Key Vault は、Azure 上で暗号化キーと Secret を管理するためのマネージドサービスです。 Key Vault を使用すると、暗号化キーと Secret を安全に保存し、アクセス制御ポリシーを適用し、監査ログを記録できます。
Azure Key Vault と Kubernetes を統合する方法はいくつかあります。
- KMS Provider for Kubernetes: KMS Provider for Kubernetes は、Kubernetes の組み込みの暗号化メカニズムを使用して、Azure Key Vault で Secret を暗号化します。
- Azure Key Vault Provider for Kubernetes: Azure Key Vault Provider for Kubernetes は、Kubernetes Secret を Azure Key Vault から動的に取得するための Kubernetes CSI (Container Storage Interface) ドライバです。
4.5 外部 Secret ストア連携のメリットとデメリット
外部 Secret ストア連携には、以下のメリットがあります。
- 集中管理: Secret を一元的に管理できるため、管理が容易になります。
- 高度なセキュリティ: 外部 Secret ストアは、暗号化、アクセス制御、監査ログなどの高度なセキュリティ機能を提供します。
- Secret のローテーション: 外部 Secret ストアは、自動的な Secret のローテーションをサポートしている場合が多く、セキュリティを向上させることができます。
一方、以下のデメリットもあります。
- 複雑さ: 外部 Secret ストアの統合には、追加の設定とインフラストラクチャが必要になります。
- 依存関係: Kubernetes クラスタが外部 Secret ストアに依存することになり、可用性に影響を与える可能性があります。
- コスト: 外部 Secret ストアの利用には、コストがかかる場合があります。
5. Secret 暗号化におけるベストプラクティス
5.1 最小権限の原則の適用
Secret へのアクセス権は、必要最小限の Pod とユーザにのみ許可する必要があります。 Kubernetes Role-Based Access Control (RBAC) を使用して、Secret へのアクセスを制御できます。
5.2 Secret のローテーション
定期的に Secret をローテーションすることで、キーが漏洩した場合のリスクを軽減できます。 Secret のローテーションは、外部 Secret ストアの機能を利用するか、カスタムスクリプトを使用して実行できます。
5.3 アクセスログの監視
Secret へのアクセスログを監視することで、不正アクセスを検出しやすくなります。 Kubernetes Audit Logs を使用して、Secret へのアクセスを監視できます。
5.4 定期的な監査
定期的な監査を実施することで、セキュリティ上の脆弱性を特定し、改善することができます。
5.5 Secret の適切なスコープ
Secret は、必要な Namespace にのみ作成する必要があります。クラスタ全体で共有する必要がない Secret は、特定の Namespace に限定することで、セキュリティリスクを軽減できます。
6. まとめ:安全な Kubernetes Secret 管理に向けて
Kubernetes Secret は、アプリケーションの機密情報を安全に管理するための重要な機能です。デフォルトの Secret 保存は安全ではないため、暗号化を有効にすることが不可欠です。 Kubernetes は、組み込みの暗号化メカニズムを提供していますが、より高度なセキュリティ要件を満たすためには、外部 Secret ストアとの連携を検討する必要があります。
Secret の暗号化、ローテーション、アクセス制御、監査ログの監視などのベストプラクティスを遵守することで、Kubernetes クラスタのセキュリティを大幅に向上させることができます。
本記事が、Kubernetes Secret の安全な管理に向けた皆様の一助となれば幸いです。 今後も、セキュリティに関する情報を継続的に学習し、実践していくことが重要です。