Secret: Kubernetes で機密情報を Pod に渡す
- 公開日
- カテゴリ:Kubernetes
- タグ:Kubernetes,学習メモ

アプリには、データベースのパスワードや API キーのように、人に見せたくない値がある。こうした値を Pod の定義やコンテナイメージに直接書くと、それを読める人全員に値が見える。
Secret は、パスワードのような機密情報をキーと値の組で保存したデータ。機密情報を、Pod の定義やコンテナイメージから切り離しておける。Pod は、Secret の値を環境変数やファイルとして受け取れる。
この記事では、Secret をローカルのクラスタに作り、値がどう表示され、どう保存されているかを確認したうえで、Pod に環境変数として渡す。
この記事でやること:
- Secret の YAML の確認
- Secret の作成と表示の確認
- ConfigMap との表示の比較
- 保存されている値の確認とデコード
- 環境変数としての受け取り
- Secret がない状態での Pod の起動
- kubectl apply が付けるアノテーションの確認
contents
- 環境
- Secret の YAML
- Secret を作る
- ConfigMap と表示を比べる
- 保存されている値を確認する
- Pod から Secret を参照する
- 環境変数として受け取る
- ConfigMap と Secret の違い
- Secret と Deployment を消す
- Secret がない状態で Pod を起動する
- kubectl apply が付けるアノテーション
- Secret を扱うときの注意
- 用語メモ
- 参考 URL
環境
kind で作ったクラスタ(Control Plane 1台 + Worker 2台)を使う。(作り方は「Kubernetes の Pod とは?コンテナを動かす最小単位を整理する」を参照)
- 環境: macOS(Apple Silicon)、Docker Desktop 29.8.0、kind v0.33.0、Kubernetes v1.37.0、kubectl v1.36.1
Secret の YAML
# db-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
username: admin
password: S3cret-Pass
| 場所 | 意味 |
|---|---|
metadata.name | Secret の名前。Pod からは、この名前で参照する |
type | Secret の種類 |
stringData | 値の本体。キーと値の組を並べる。値はエンコードせずに、そのままの文字列で書く |
Opaqueは、任意のユーザー定義データを入れる種類。typeを省略した場合もOpaqueになるOpaqueのほかに、用途の決まった種類がある。たとえばkubernetes.io/tlsは TLS の証明書と鍵を入れる種類で、キーtls.crtとtls.keyが必要- 値を書くフィールドには、
stringDataのほかにdataがある。dataには、base64 でエンコードした値を書く S3cret-Passは、この記事用のダミーのパスワード。実際に使っているものではない
Secret を作る
$ kubectl apply -f db-secret.yaml
# => secret/db-secret created
$ kubectl get secrets
NAME TYPE DATA AGE
db-secret Opaque 2 16s
TYPEは、YAML のtypeに書いたOpaqueDATAの2は、キーの数
kubectl describe で見る。
$ kubectl describe secret db-secret
Name: db-secret
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password: 11 bytes
username: 5 bytes
Data に表示されるのは、キーと値のバイト数。値そのものは表示されない。
kubectl get と kubectl describe は、既定では Secret の内容を表示しない。Secret が誤って人目に触れたり、ターミナルのログに残ったりするのを防ぐため。
Secret はどこにあるか
Secret は、動いているプログラムではなく、YAML に書いた内容が記録されたデータ(オブジェクト)。ConfigMap や Deployment と同じく、Control Plane で動いている etcd に保存される。(「ConfigMap: Kubernetes で Pod に渡す設定値」の「ConfigMap はどこにあるか」を参照)
- Secret、Deployment、ReplicaSet は、Control Plane の etcd に保存されたデータ。Control Plane で動いているプログラムではない
- 図のうち、Node の上にあるのは Pod だけ
- 矢印は、そのデータが何についての定義かを示す。データ自身が何かを作ったり渡したりするわけではない
- Deployment
demo-appと Pod は、このあと作るもの - Secret を作っただけでは、Pod は増えない。どの Node の上でも何も動かない
- Secret のデータを取得するのは、Secret を参照する Pod が置かれた Node の kubelet。Secret は、それを必要とする Pod がある Node にだけ送られる
- Secret は、既定では暗号化されずに etcd に保存される
ConfigMap と表示を比べる
ConfigMap は、機密性のない設定の値をキーと値の組で保存したデータ。同じ値を ConfigMap にも入れて、kubectl describe の表示を比べる。
$ kubectl create configmap db-config --from-literal=password=S3cret-Pass
# => configmap/db-config created
$ kubectl describe configmap db-config
Name: db-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
password:
----
S3cret-Pass
BinaryData
====
Events: <none>
kubectl describe の Data の表示 | |
|---|---|
ConfigMap db-config | キーと値 |
Secret db-secret | キーと値のバイト数 |
保存されている値を確認する
kubectl describe では表示されなかった値を、kubectl get の -o jsonpath で取り出す。
$ kubectl get secret db-secret -o jsonpath='{.data}'
# => {"password":"UzNjcmV0LVBhc3M=","username":"YWRtaW4="}
$ kubectl get configmap db-config -o jsonpath='{.data}'
# => {"password":"S3cret-Pass"}
| 部分 | 意味 |
|---|---|
kubectl get secret db-secret | Secret db-secret を取得する |
-o jsonpath='{.data}' | 取得した内容のうち、data フィールドだけを出力する |
- YAML では
stringDataに書いた値が、dataに入っている。stringDataのキーと値は、内部でdataにマージされる - Secret の
passwordの値は、YAML に書いたS3cret-PassではなくUzNjcmV0LVBhc3M= - ConfigMap の
passwordの値は、S3cret-Passのまま
base64 のデコード
UzNjcmV0LVBhc3M= は、S3cret-Pass を base64 でエンコードした文字列。base64 は、データを英数字と一部の記号だけの文字列で表すエンコード方式。
base64 コマンドでデコードする。
$ echo 'UzNjcmV0LVBhc3M=' | base64 --decode
# => S3cret-Pass
base64 --decodeだけで、YAML に書いた値に戻った。鍵やパスワードは使っていない- base64 エンコードは暗号化の方式ではない。平文と比べて機密性は高くならない
| 値 | |
|---|---|
YAML の stringData に書いた値 | S3cret-Pass |
Secret の data に入っている値 | UzNjcmV0LVBhc3M= |
| デコードした値 | S3cret-Pass |
Pod から Secret を参照する
どの Secret を使うかは、Deployment の YAML に書く。
Pod を1つ動かす Deployment を用意する。(Deployment については「Deployment: Kubernetes で Pod の数と更新を管理する」を参照)
# demo-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: nginx
image: nginx:1.16.1
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
Secret を参照しているのは、env の secretKeyRef。この YAML に S3cret-Pass という値は書かれていない。書かれているのは、Secret の名前とキー。
コンテナの image は nginx だが、nginx の機能は使わない。動き続けるコンテナとして使っている。
$ kubectl apply -f demo-deployment.yaml
# => deployment.apps/demo-app created
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo-app-59c945db57-vr9lp 1/1 Running 0 12s 10.244.2.2 k8s-study-worker2 <none> <none>
環境変数として受け取る
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
| 場所 | 意味 |
|---|---|
env.name | コンテナに設定する環境変数の名前 |
secretKeyRef.name | 参照する Secret の名前 |
secretKeyRef.key | その Secret の中のキー。このキーの値が、環境変数の値になる |
Pod のコンテナの中で、環境変数を表示する。
$ kubectl exec deploy/demo-app -- printenv DB_USERNAME
# => admin
$ kubectl exec deploy/demo-app -- printenv DB_PASSWORD
# => S3cret-Pass
| 部分 | 意味 |
|---|---|
kubectl exec | Pod のコンテナの中でコマンドを実行する |
deploy/demo-app | Deployment demo-app の Pod を対象にする。Pod の名前を指定しなくて済む |
-- printenv DB_PASSWORD | コンテナの中で実行するコマンド。環境変数 DB_PASSWORD の値を表示する |
- Secret の値が、コンテナの環境変数に入っている
- 環境変数の値は、base64 の文字列(
UzNjcmV0LVBhc3M=)ではなく、デコードされた値(S3cret-Pass)
Pod の情報での表示
kubectl describe pod の出力から、環境変数の部分を取り出す。
$ kubectl describe pod -l app=demo-app | grep -A 2 "Environment:"
Environment:
DB_USERNAME: <set to the key 'username' in secret 'db-secret'> Optional: false
DB_PASSWORD: <set to the key 'password' in secret 'db-secret'> Optional: false
| 部分 | 意味 |
|---|---|
kubectl describe pod -l app=demo-app | ラベル app=demo-app が付いた Pod の詳細を表示する |
grep -A 2 "Environment:" | Environment: の行と、その後ろの2行だけを表示する |
- 環境変数の値は表示されていない。表示されているのは、参照先の Secret の名前とキー
ConfigMap と Secret の違い
ここまでで確認した違い。
| ConfigMap | Secret | |
|---|---|---|
| 用途 | 機密性のないデータ | 機密データ |
kubectl describe の Data の表示 | キーと値 | キーと値のバイト数 |
data に入っている値 | そのままの値 | base64 でエンコードされた値 |
| 環境変数から参照する指定 | configMapKeyRef | secretKeyRef |
- どちらも、etcd に保存されたキーと値の組
- どちらも、どれを使うかは Deployment の YAML に書く
- Secret も、ConfigMap と同じく volume としてマウントして、ファイルとして受け取れる(この記事では試していない)
Secret と Deployment を消す
Deployment、Secret、ConfigMap は別々のオブジェクトなので、それぞれ消す。
$ kubectl delete -f demo-deployment.yaml
# => deployment.apps "demo-app" deleted from default namespace
$ kubectl delete -f db-secret.yaml
# => secret "db-secret" deleted from default namespace
$ kubectl delete configmap db-config
# => configmap "db-config" deleted from default namespace
$ kubectl get secrets
# => No resources found in default namespace.
Secret がない状態で Pod を起動する
Secret を作らずに、Deployment だけを apply する。
$ kubectl apply -f demo-deployment.yaml
# => deployment.apps/demo-app created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
demo-app-59c945db57-7hrmk 0/1 CreateContainerConfigError 0 6s
STATUS は CreateContainerConfigError。kubectl describe pod の Events: は次のとおり。
$ kubectl describe pod -l app=demo-app
(省略)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 22s default-scheduler Successfully assigned default/demo-app-59c945db57-7hrmk to k8s-study-worker
Normal Pulled 8s (x3 over 22s) kubelet spec.containers{nginx}: Container image "nginx:1.16.1" already present on machine and can be accessed by the pod
Warning Failed 8s (x3 over 22s) kubelet spec.containers{nginx}: Error: secret "db-secret" not found
- Pod は Node(
k8s-study-worker)に割り当てられている - kubelet の
Failedに、secret "db-secret" not foundと出ている PulledとFailedは、22 秒の間に3回ずつ記録されている(x3 over 22s)- Secret の参照は、
optionalにしていなければ必須。必須の Secret がすべて利用できるようになるまで、Pod のコンテナは起動しない - Secret を取得できない場合、kubelet は定期的にリトライする
kubectl apply が付けるアノテーション
Secret を作り直して、-o yaml で、保存されている内容の全体を表示する。
$ kubectl apply -f db-secret.yaml
# => secret/db-secret created
$ kubectl get secret db-secret -o yaml
apiVersion: v1
data:
password: UzNjcmV0LVBhc3M=
username: YWRtaW4=
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"db-secret","namespace":"default"},"stringData":{"password":"S3cret-Pass","username":"admin"},"type":"Opaque"}
creationTimestamp: "2026-10-01T12:34:20Z"
name: db-secret
namespace: default
resourceVersion: "93684"
uid: 70ebd563-092f-4bcf-a8da-f300d097235f
type: Opaque
dataの値は、base64 でエンコードされているmetadata.annotationsのkubectl.kubernetes.io/last-applied-configurationには、stringDataに書いた値(S3cret-Pass)がそのまま入っている- このアノテーションは、
kubectl applyがオブジェクトに付けるもの。中身は、オブジェクトの作成に使った設定ファイルの内容 kubectl describe secretの出力では、Annotations:は<none>と表示されていた
stringData に値を書いた YAML を kubectl apply すると、Secret の data とは別に、エンコードされていない値がアノテーションにも保存される。
Secret を扱うときの注意
公式ドキュメントにある、Secret についての注意点。
- Secret は、既定では暗号化されずに etcd に保存される
- API にアクセスできる人は、Secret を取得・変更できる。etcd にアクセスできる人も同様
- namespace に Pod を作る権限がある人は、その権限を使って、その namespace の Secret を読める。Deployment を作る権限のような間接的なものも含む
- Secret のマニフェスト(YAML)を共有したり、ソースリポジトリに入れたりすると、マニフェストを読める全員に機密情報が渡る。値を base64 でエンコードしてあっても同じ
同じく公式ドキュメントで、Secret を安全に使うために挙げられていること。
- etcd に保存するデータの暗号化
- Secret への最小権限のアクセス設定(RBAC)
- Secret にアクセスできるコンテナの限定
- クラスタの外にある Secret ストアの利用
Secret の作り方ごとの、値が手元に残る場所。
- YAML を書いて
kubectl applyで作る方法では、YAML ファイル(db-secret.yaml)に値がそのまま残る - YAML を書かずに
kubectl create secret generic db-secret --from-literal=password=...で作る方法もある。YAML ファイルは残らないが、値を含むコマンドがシェルの履歴に残る
用語メモ
| 用語 | 読み方 | 意味 |
|---|---|---|
| Secret | シークレット | パスワード、トークン、鍵のような機密データを保存するオブジェクト |
| Opaque | オペーク | Secret の種類の1つ。任意のユーザー定義データ |
| stringData | ストリングデータ | Secret の値を、エンコードしていない文字列で書くフィールド |
| base64 | ベースろくじゅうよん | データを英数字と一部の記号だけの文字列で表すエンコード方式。暗号化ではない |
| secretKeyRef | シークレット キー レフ | 環境変数の値として、Secret の特定のキーを参照する指定 |
まとめ
- Secret は、パスワードのような機密情報をキーと値の組で保存したデータ。動いているプログラムではなく、etcd に保存される
kubectl getとkubectl describeは、Secret の値を表示しない- Secret の値は、base64 でエンコードされて
dataに入る。base64 は暗号化ではなく、デコードすれば元の値に戻る - どの Secret を使うかは、Deployment の YAML に書く。環境変数として受け取るには、
envのsecretKeyRefで Secret の名前とキーを指定する - コンテナの環境変数には、デコードされた値が入る
- 参照先の Secret が存在しないと、Pod のコンテナは起動しない
stringDataに値を書いた YAML をkubectl applyすると、エンコードされていない値がアノテーションにも保存される- Secret は、既定では暗号化されずに etcd に保存される。Secret を取得できる人、Pod を作れる人は、値を読める
参考 URL
- [official] Secret | Kubernetes
- [official] Kubernetes Secretの適切な使用方法 | Kubernetes
- [official] kubectlを使用してSecretを管理する | Kubernetes
- [official] 設定ファイルを使用してSecretを管理する | Kubernetes
- [official] Secretsで安全にクレデンシャルを配布する | Kubernetes
- [official] Encrypting Confidential Data at Rest | Kubernetes
- [official] Declarative Management of Kubernetes Objects Using Configuration Files | Kubernetes

