Kubernetes Secret徹底解説:設定例とセキュリティ対策
Kubernetes(以下、k8s)におけるSecretは、パスワード、APIキー、証明書などの機密情報を安全に管理するためのオブジェクトです。Podの定義ファイルやイメージに直接機密情報を記述する代わりに、Secretオブジェクトに格納し、必要な時にPodから参照することで、セキュリティリスクを軽減し、機密情報の管理を効率化します。本記事では、k8s Secretの基本的な概念から、具体的な設定例、セキュリティ対策までを詳細に解説します。
1. Secretとは
k8s Secretは、機密情報を安全に格納し、Podに提供するためのオブジェクトです。具体的には、以下のような情報を格納するために使用されます。
- パスワード: データベース、外部サービス、APIのエンドポイントなどにアクセスするための認証情報。
- APIキー: 外部サービスやAPIを利用するための認証トークン。
- 証明書: TLS/SSL通信を確立するための証明書と秘密鍵。
- その他機密情報: 設定ファイル、SSHキー、暗号化キーなど、アプリケーションの動作に必要な機密性の高い情報。
1.1 Secretの重要性
Secretを使用する主な理由は以下の通りです。
- セキュリティ向上: Podの定義ファイルやイメージに機密情報を記述することを避け、ソースコードリポジトリに機密情報が漏洩するリスクを軽減します。
- 機密情報の集中管理: 機密情報をSecretオブジェクトとして一元的に管理することで、管理の手間を軽減し、機密情報の更新やローテーションを容易にします。
- アクセス制御: SecretオブジェクトへのアクセスをRBAC(Role-Based Access Control)で制御することで、承認されたユーザーやサービスアカウントのみが機密情報にアクセスできるように制限します。
- Podの可搬性向上: Podの定義ファイルから機密情報を分離することで、Podを異なる環境に簡単にデプロイできます。
- 監査可能性: Secretオブジェクトの作成、更新、削除などの操作は、k8sの監査ログに記録されるため、機密情報の利用状況を追跡できます。
1.2 Secretの種類
k8sには、いくつかの組み込みのSecretタイプがあります。
- Opaque: 最も一般的なSecretタイプで、任意の形式の機密情報を格納できます。Base64エンコードされたkey-valueペアとしてデータを格納します。
- kubernetes.io/dockerconfigjson: Dockerレジストリへの認証情報を格納するためのSecretタイプ。
.dockerconfigjson
ファイルの内容を格納します。 - kubernetes.io/service-account-token: サービスアカウントに関連付けられたトークンを格納するためのSecretタイプ。Podがk8s APIサーバーにアクセスするために使用されます。
- kubernetes.io/tls: TLS/SSL証明書と秘密鍵を格納するためのSecretタイプ。TLS/SSL通信を確立するために使用されます。
- bootstrap.kubernetes.io/token: ノードのブートストラップに使用されるトークンを格納するためのSecretタイプ。
これらのSecretタイプに加えて、カスタムSecretタイプを定義することも可能です。
2. Secretの設定方法
Secretを設定するには、kubectl
コマンドラインツールまたはYAMLファイルを使用します。
2.1 kubectlコマンドによるSecret作成
kubectl create secret
コマンドを使用して、コマンドラインからSecretを作成できます。
bash
kubectl create secret generic my-secret \
--from-literal=username=admin \
--from-literal=password=secretpassword
このコマンドは、my-secret
という名前のOpaqueタイプのSecretを作成し、username
とpassword
という2つのkey-valueペアを格納します。--from-literal
オプションは、コマンドラインから直接値を指定するために使用されます。
別の方法として、ファイルからSecretを作成することもできます。
bash
kubectl create secret generic my-secret \
--from-file=username=./username.txt \
--from-file=password=./password.txt
このコマンドは、username.txt
ファイルとpassword.txt
ファイルの内容をそれぞれusername
とpassword
というキーに対応する値として格納します。
2.2 YAMLファイルによるSecret作成
YAMLファイルを使用してSecretを定義することもできます。
yaml
apiVersion: v1
kind: Secret
metadata:
name: my-secret
type: Opaque
data:
username: YWRtaW4=
password: c2VjcmV0cGFzc3dvcmQ=
このYAMLファイルは、my-secret
という名前のOpaqueタイプのSecretを定義し、username
とpassword
という2つのkey-valueペアを格納します。data
フィールドには、Base64エンコードされた値が含まれていることに注意してください。
YAMLファイルを使用してSecretを作成するには、kubectl apply
コマンドを使用します。
bash
kubectl apply -f my-secret.yaml
2.3 Dockerconfigjson Secretの作成
Dockerレジストリへの認証情報を格納するためのkubernetes.io/dockerconfigjson
タイプのSecretを作成するには、.dockerconfigjson
ファイルが必要です。
bash
kubectl create secret docker-registry my-docker-secret \
--docker-server=YOUR_REGISTRY_SERVER \
--docker-username=YOUR_USERNAME \
--docker-password=YOUR_PASSWORD \
--docker-email=YOUR_EMAIL
このコマンドは、my-docker-secret
という名前のkubernetes.io/dockerconfigjson
タイプのSecretを作成し、指定されたDockerレジストリの認証情報を格納します。
2.4 TLS Secretの作成
TLS/SSL証明書と秘密鍵を格納するためのkubernetes.io/tls
タイプのSecretを作成するには、証明書ファイルと秘密鍵ファイルが必要です。
bash
kubectl create secret tls my-tls-secret \
--cert=path/to/tls.crt \
--key=path/to/tls.key
このコマンドは、my-tls-secret
という名前のkubernetes.io/tls
タイプのSecretを作成し、指定された証明書と秘密鍵を格納します。
3. Secretの使用方法
Secretを作成したら、Podで使用できます。SecretをPodで使用する方法はいくつかあります。
- 環境変数として: Secretの値をPodの環境変数として設定します。
- ボリュームとして: Secretの内容をPodのファイルシステムにマウントします。
- イメージプルシークレットとして: Dockerレジストリからイメージをプルするための認証情報として使用します。
3.1 環境変数としてSecretを使用する
Secretの値をPodの環境変数として設定するには、Podの定義ファイルでenv
フィールドを使用します。
yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx
env:
- name: USERNAME
valueFrom:
secretKeyRef:
name: my-secret
key: username
- name: PASSWORD
valueFrom:
secretKeyRef:
name: my-secret
key: password
この例では、my-pod
という名前のPodのmy-container
という名前のコンテナに対して、USERNAME
とPASSWORD
という2つの環境変数を設定しています。valueFrom
フィールドを使用して、my-secret
という名前のSecretからそれぞれの値を取得しています。secretKeyRef
フィールドは、Secretの名前と、環境変数の値として使用するSecret内のキーを指定します。
3.2 ボリュームとしてSecretを使用する
Secretの内容をPodのファイルシステムにマウントするには、Podの定義ファイルでvolumes
とvolumeMounts
フィールドを使用します。
yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: nginx
volumeMounts:
- name: my-secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: my-secret-volume
secret:
secretName: my-secret
この例では、my-pod
という名前のPodのmy-container
という名前のコンテナに対して、my-secret-volume
という名前のボリュームを/etc/secrets
ディレクトリにマウントしています。volumes
フィールドで、my-secret-volume
という名前のボリュームを定義し、secret
フィールドを使用して、my-secret
という名前のSecretを参照しています。readOnly: true
を指定することで、コンテナがSecretの内容を変更できないようにしています。
Secretをボリュームとしてマウントすると、Secret内の各key-valueペアが、マウントされたディレクトリ内のファイルとして表現されます。例えば、my-secret
Secretにusername
とpassword
という2つのキーが含まれている場合、/etc/secrets
ディレクトリには、username
ファイルとpassword
ファイルが作成されます。
3.3 イメージプルシークレットとしてSecretを使用する
Dockerレジストリからイメージをプルするための認証情報としてSecretを使用するには、Podの定義ファイルでimagePullSecrets
フィールドを使用します。
yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: your-registry/your-image:latest
imagePullSecrets:
- name: my-docker-secret
この例では、my-pod
という名前のPodは、your-registry/your-image:latest
というイメージをプルするために、my-docker-secret
という名前のSecretを使用します。imagePullSecrets
フィールドは、イメージをプルするために使用するSecretの名前を指定します。
4. Secretのセキュリティ対策
Secretには機密情報が含まれているため、適切なセキュリティ対策を講じることが重要です。
4.1 RBACによるアクセス制御
RBAC(Role-Based Access Control)を使用して、Secretオブジェクトへのアクセスを制御します。承認されたユーザーやサービスアカウントのみがSecretを作成、更新、削除、および参照できるように制限します。
RoleとRoleBindingを使用して、特定のネームスペース内のSecretに対するアクセス権を定義できます。ClusterRoleとClusterRoleBindingを使用して、クラスター全体のSecretに対するアクセス権を定義できます。
例えば、以下のRoleは、my-namespace
ネームスペース内のすべてのSecretに対する読み取りアクセス権を付与します。
yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
namespace: my-namespace
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
以下のRoleBindingは、my-service-account
という名前のサービスアカウントに、上記のRoleを割り当てます。
yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: secret-reader-binding
namespace: my-namespace
subjects:
- kind: ServiceAccount
name: my-service-account
namespace: my-namespace
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
4.2 暗号化された保存
k8s APIサーバーは、etcdという分散キーバリューストアにすべてのクラスタデータを格納します。デフォルトでは、etcdに格納されたSecretは暗号化されていません。そのため、etcdへのアクセス権を持つ人は誰でもSecretの内容を読み取ることができます。
Secretを安全に保管するために、etcdに格納されるSecretを暗号化することをお勧めします。k8sでは、Encryption Configurationを使用して、etcdに格納されるSecretを暗号化できます。
Encryption Configurationファイルは、暗号化プロバイダーと暗号化キーを指定します。k8sは、Encryption Configurationファイルに基づいて、etcdに格納されるSecretを自動的に暗号化および復号化します。
4.3 Secretのローテーション
Secretの内容は定期的にローテーションすることをお勧めします。Secretのローテーションは、セキュリティ侵害が発生した場合の影響を軽減し、機密情報の有効期間を制限します。
Secretのローテーションは、手動で行うことも、自動化することもできます。手動でSecretをローテーションするには、新しいSecretを作成し、古いSecretを使用しているPodを更新します。自動化されたSecretローテーションには、Sealed Secrets、HashiCorp Vaultなどのツールを使用できます。
4.4 Secretの監査
k8sの監査ログを有効にして、Secretの作成、更新、削除などの操作を追跡します。監査ログを分析することで、Secretへの不正アクセスや不正使用を検出できます。
4.5 Secretの最小権限の原則
Podに必要なSecretのみを提供し、不要なSecretへのアクセスを制限します。最小権限の原則に従うことで、セキュリティ侵害が発生した場合の影響を軽減できます。
4.6 Sealed Secretsによる安全な保管
Sealed Secretsは、Secretを暗号化し、GitHubなどのパブリックリポジトリに安全に保管できるようにするk8sコントローラーです。Sealed Secretsを使用すると、機密情報をソースコードリポジトリにコミットするリスクを軽減できます。
Sealed Secretsは、マスター公開鍵とマスター秘密鍵を使用してSecretを暗号化します。マスター公開鍵は誰でも利用できますが、マスター秘密鍵はクラスター管理者のみがアクセスできます。Sealed Secretsコントローラーは、マスター秘密鍵を使用して、クラスターにデプロイされたSecretを復号化します。
4.7 HashiCorp Vaultとの連携
HashiCorp Vaultは、機密情報を安全に保管、アクセス、および配布するためのツールです。k8sとHashiCorp Vaultを連携させることで、SecretをVaultに保管し、PodからVaultにアクセスしてSecretを取得できます。
Vaultには、アクセス制御、監査、ローテーションなどの機能が組み込まれており、Secretのセキュリティを向上させることができます。
5. まとめ
k8s Secretは、パスワード、APIキー、証明書などの機密情報を安全に管理するための重要なオブジェクトです。Secretを使用することで、セキュリティリスクを軽減し、機密情報の管理を効率化できます。
本記事では、k8s Secretの基本的な概念から、具体的な設定例、セキュリティ対策までを詳細に解説しました。これらの情報を活用して、安全で効率的なk8s環境を構築してください。
今後の学習
- Secret Generator: Secretを自動的に生成する仕組みを理解する。
- External Secrets Operator: 外部のSecret管理システム(AWS Secrets Manager、Azure Key Vaultなど)と連携する。
- Kustomize: Secretを含むYAMLファイルをカスタマイズする。
- Helm: SecretをHelmチャートで管理する。
これらのトピックを学ぶことで、k8s Secretの理解をさらに深め、より高度なセキュリティ対策を講じることができます。