Kubernetesをやってみる - Secretで機密情報を管理する
はじめに
この記事では、Kubernetes の Secret について、概念から実践的なハンズオンまで解説します。
Secret を理解することで、パスワードやトークンなどの機密情報を安全に管理できるようになります。
Secret とは
Secret は、パスワードやトークンなどの機密情報を保存する Kubernetes リソースです。
ConfigMap と似ていますが、機密データを扱うために設計されています。
┌─────────────────────────────────────────────────────────┐
│ Secret │
│ ┌─────────────────┬─────────────────────────────────┐ │
│ │ Key │ Value (Base64) │ │
│ ├─────────────────┼─────────────────────────────────┤ │
│ │ db.user │ dXNlcg== │ │
│ │ db.password │ cGFzc3dvcmQ= │ │
│ └─────────────────┴─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Pod │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Container │ │
│ │ 環境変数: │ │
│ │ DB_USER=user │ │
│ │ DB_PASSWORD=password │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Base64 エンコードについて
# エンコード
echo -n "password" | base64
# cGFzc3dvcmQ=
# デコード(簡単に元に戻せる)
echo "cGFzc3dvcmQ=" | base64 -d
# password
つまり、Secret の YAML ファイルを Git にコミットすると、パスワードが漏洩します。
Secret の種類
| タイプ | 用途 |
|---|---|
Opaque |
汎用的な機密情報(デフォルト) |
kubernetes.io/dockerconfigjson |
Docker レジストリの認証情報 |
kubernetes.io/tls |
TLS 証明書 |
kubernetes.io/basic-auth |
Basic 認証 |
このハンズオンでは Opaque(汎用)を使います。
Secret の使い方
ConfigMap と同じく 4 つの方法がありますが、実務で主に使うのは 2 つです。
| 方法 | 説明 | 使用頻度 |
|---|---|---|
| 環境変数(個別キー) |
secretKeyRef で特定のキーを指定 |
★★★ |
| 環境変数(一括) |
envFrom で全キーを一括設定 |
★☆☆ |
| ボリュームマウント | ファイルとしてマウント | ★★☆ |
| コマンドライン引数 | 環境変数経由で参照 | ★☆☆ |
環境変数(個別キー)
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret # Secret の名前
key: db.password # キー名
ボリュームマウント
volumeMounts:
- name: secret-volume
mountPath: /etc/secret
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: app-secret
更新時の挙動
| 使い方 | 更新反映 |
|---|---|
| 環境変数 | Pod 再起動が必要 |
| ボリュームマウント | 自動反映(最大1分程度の遅延) |
ConfigMap vs Secret
| 項目 | ConfigMap | Secret |
|---|---|---|
| 用途 | 一般的な設定値 | 機密情報(パスワード等) |
| データ形式 | プレーンテキスト | Base64 エンコード |
| Git 管理 | OK | NG(漏洩の危険) |
| etcd 保存 | プレーンテキスト | 暗号化可能 |
本番環境での Secret 管理
Secret を Git で管理しないなら、どうやって管理するのか?
| 方法 | 説明 |
|---|---|
| 外部シークレット管理 | AWS Secrets Manager, HashiCorp Vault などから取得 |
| Sealed Secrets | 暗号化した Secret を Git 管理 |
| SOPS | YAML ファイルを暗号化 |
| External Secrets Operator | 外部サービスと Kubernetes を連携 |
minikube での学習では、これらは使わずに直接 Secret を作成します。
ハンズオン
ここからは実際に手を動かして Secret の動作を確認します。
やること
実務でよく使う 2 つの方法(環境変数・ボリュームマウント)を順番に試します。
| Step | 内容 |
|---|---|
| Step 1 | Secret を作成する |
| Step 2 | 環境変数で使う(Pod 作成 → 確認 → 更新 → 反映確認) |
| Step 3 | ボリュームマウントで使う(Pod 作成 → 確認 → 更新 → 反映確認) |
| Step 4 | クリーンアップ |
事前準備
# kind クラスターが起動していることを確認
k cluster-info
Step 1: Secret を作成する
Secret の作成方法は 2 つあります。どちらか一方を実行してください。
方法A: コマンドで作成
k create secret generic app-secret \
--from-literal=db.user=myuser \
--from-literal=db.password=mypassword
方法B: YAML マニフェストで作成
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
# echo -n "myuser" | base64
db.user: bXl1c2Vy
# echo -n "mypassword" | base64
db.password: bXlwYXNzd29yZA==
k apply -f secret.yaml
確認
Secret が作成されたか確認します。
k get secret
NAME TYPE DATA AGE
app-secret Opaque 2 5s ← DATA=2 で2件のキーがある
Secret の中身を確認します。
k describe secret app-secret
Name: app-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
db.password: 10 bytes
db.user: 6 bytes
値を確認したい場合は -o yaml を使います。
k get secret app-secret -o yaml
apiVersion: v1
data:
db.password: bXlwYXNzd29yZA== ← Base64 エンコードされている
db.user: bXl1c2Vy
kind: Secret
# ...
Base64 デコードして確認できます。
echo "bXlwYXNzd29yZA==" | base64 -d
# mypassword
Step 2: 環境変数で使う
Pod を作成
apiVersion: v1
kind: Pod
metadata:
name: secret-demo-env
spec:
containers:
- name: app
image: busybox:latest
command: ["sleep", "3600"]
env:
- name: DB_USER
valueFrom:
secretKeyRef:
name: app-secret
key: db.user
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secret
key: db.password
k apply -f pod-env.yaml
環境変数を確認
Pod が Running になったら、中に入って確認します。
k exec -it secret-demo-env -- sh
/ # env | grep DB_
DB_USER=myuser ← Secret の値が環境変数に入っている
DB_PASSWORD=mypassword
/ # exit
Secret で設定した値が DB_USER, DB_PASSWORD として入っていれば OK です。
Pod 内では Base64 デコードされた状態で参照できます。
Secret を更新して反映を確認
k delete secret app-secret
k create secret generic app-secret \
--from-literal=db.user=newuser \
--from-literal=db.password=newpassword
k exec secret-demo-env -- env | grep DB_
# DB_USER=myuser ← まだ古い値のまま
Pod を再作成すると反映されます。
k delete pod secret-demo-env
k apply -f pod-env.yaml
k exec secret-demo-env -- env | grep DB_
# DB_USER=newuser ← 更新された!
クリーンアップ
k delete -f pod-env.yaml
Step 3: ボリュームマウントで使う
Pod を作成
apiVersion: v1
kind: Pod
metadata:
name: secret-demo-volume
spec:
containers:
- name: app
image: busybox:latest
command: ["sleep", "3600"]
volumeMounts:
- name: secret-volume
mountPath: /etc/secret
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: app-secret
k apply -f pod-volume.yaml
マウントされたファイルを確認
Pod が Running になったら、中に入って確認します。
k exec -it secret-demo-volume -- sh
/ # ls /etc/secret
db.password
db.user
/ # cat /etc/secret/db.password
newpassword
/ # exit
Secret の各キーがファイルとして /etc/secret/ に存在し、中身が値と一致していれば OK です。
Secret を更新して反映を確認
k delete secret app-secret
k create secret generic app-secret \
--from-literal=db.user=volumeuser \
--from-literal=db.password=volumepassword
# 少し待ってから確認(最大1分程度の遅延あり)
k exec secret-demo-volume -- cat /etc/secret/db.password
# volumepassword ← Pod 再起動なしで更新された!
クリーンアップ
k delete -f pod-volume.yaml
Step 4: クリーンアップ
# 方法B(YAML)で作成した場合
k delete -f secret.yaml
# 方法A(コマンド)で作成した場合
k delete secret app-secret
よく使うコマンドまとめ
# 作成
k create secret generic <name> --from-literal=key=value
k apply -f secret.yaml
# 確認
k get secret
k describe secret <name>
k get secret <name> -o yaml
# 値をデコードして確認
k get secret <name> -o jsonpath='{.data.key}' | base64 -d
# 削除
k delete secret <name>
まとめ
- Secret はパスワードやトークンなどの機密情報を管理するリソース
- Base64 エンコードは暗号化ではないため、Git にコミットしない
- 環境変数とボリュームマウントの 2 つの使い方が主流
- 環境変数は Pod 再起動が必要、ボリュームマウントは自動反映
- 本番環境では外部シークレット管理(AWS Secrets Manager 等)を検討する
Discussion