Ritolabo
  1. Home
  2. Kubernetes
  3. Secret: Kubernetes で機密情報を Pod に渡す

Secret: Kubernetes で機密情報を Pod に渡す

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

アプリには、データベースのパスワードや API キーのように、人に見せたくない値がある。こうした値を Pod の定義やコンテナイメージに直接書くと、それを読める人全員に値が見える。

Secret は、パスワードのような機密情報をキーと値の組で保存したデータ。機密情報を、Pod の定義やコンテナイメージから切り離しておける。Pod は、Secret の値を環境変数やファイルとして受け取れる。

この記事では、Secret をローカルのクラスタに作り、値がどう表示され、どう保存されているかを確認したうえで、Pod に環境変数として渡す。

この記事でやること:

  • Secret の YAML の確認
  • Secret の作成と表示の確認
  • ConfigMap との表示の比較
  • 保存されている値の確認とデコード
  • 環境変数としての受け取り
  • Secret がない状態での Pod の起動
  • kubectl apply が付けるアノテーションの確認

contents

  1. 環境
  2. Secret の YAML
  3. Secret を作る
    1. Secret はどこにあるか
  4. ConfigMap と表示を比べる
  5. 保存されている値を確認する
    1. base64 のデコード
  6. Pod から Secret を参照する
  7. 環境変数として受け取る
    1. Pod の情報での表示
  8. ConfigMap と Secret の違い
  9. Secret と Deployment を消す
  10. Secret がない状態で Pod を起動する
  11. kubectl apply が付けるアノテーション
  12. Secret を扱うときの注意
  13. 用語メモ
  14. 参考 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.nameSecret の名前。Pod からは、この名前で参照する
typeSecret の種類
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 に書いた Opaque
  • DATA の 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-secretSecret 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 execPod のコンテナの中でコマンドを実行する
deploy/demo-appDeployment 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 の違い

ここまでで確認した違い。

ConfigMapSecret
用途機密性のないデータ機密データ
kubectl describe の Data の表示キーと値キーと値のバイト数
data に入っている値そのままの値base64 でエンコードされた値
環境変数から参照する指定configMapKeyRefsecretKeyRef
  • どちらも、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


[Prev] ConfigMap: Kubernetes で Pod に渡す設定値

Author

rito

rito

  • Backend Engineer
  • Tokyo, Japan
  • PHP 5 技術者認定上級試験 認定者
  • 統計検定 3 級