目的
- secretsとserviceaccountを理解する
手段
killercodaで手を動かす
環境
killercoda
secrets とは
secrets は k8s 上でパスワード・トークン・キーを保存するオブジェクトです。パスワード等を secrets に格納して、pod 等から参照して利用します。利用方法は pod の環境変数として代入する、または、pod 内の特定パスに対して volume マウントして利用します。
secret 作成
まず、secret を作成します。
controlplane:~$ k create secret generic holy --from-literal creditcard=1111222233334444 --dry-run=client -oyaml
apiVersion: v1
data:
creditcard: MTExMTIyMjIzMzMzNDQ0NA==
kind: Secret
metadata:
creationTimestamp: null
name: holy
# 作成前に yaml フォーマットで確認します
controlplane:~$ k get secrets holy
NAME TYPE DATA AGE
holy Opaque 1 8s
# 作成したオブジェクトを確認します
controlplane:~$ k get secrets holy -oyaml
apiVersion: v1
data:
creditcard: MTExMTIyMjIzMzMzNDQ0NA==
kind: Secret
metadata:
creationTimestamp: "2025-04-15T02:19:31Z"
name: holy
namespace: default
resourceVersion: "6739"
uid: 05b43f90-68c6-4454-926f-513a643bb671
# 作成した値は base64 でエンコード後の値で保持されます
# つまり、このオブジェクトを参照可能なユーザは チルダcreditcardチルダ の値をデコードして参照可能です
secrets 作成方法は literal と呼ばれる直接値を指定する方法やファイルから作成可能です。literal の作成方法は前述の作成方法です。次に、ファイルから secrets を作成します。
controlplane:~$ cat /opt/ks/secret-diver.yaml
apiVersion: v1
data:
hosts: MTI3LjAuMC4xCWxvY2FsaG9zdAoxMjcuMC4xLjEJaG9zdDAxCgojIFRoZSBmb2xsb3dpbmcgbGluZXMgYXJlIGRlc2lyYWJsZSBmb3IgSVB2NiBjYXBhYmxlIGhvc3RzCjo6MSAgICAgbG9jYWxob3N0IGlwNi1sb2NhbGhvc3QgaXA2LWxvb3BiYWNrCmZmMDI6OjEgaXA2LWFsbG5vZGVzCmZmMDI6OjIgaXA2LWFsbHJvdXRlcnMKMTI3LjAuMC4xIGhvc3QwMQoxMjcuMC4wLjEgaG9zdDAxCjEyNy4wLjAuMSBob3N0MDEKMTI3LjAuMC4xIGNvbnRyb2xwbGFuZQoxNzIuMTcuMC4zNSBub2RlMDEKMTcyLjE3LjAuMjMgY29udHJvbHBsYW5lCg== # hosts は key となり、エンコードされた文字列は value となります
kind: Secret
metadata:
name: diver # secret のオブジェクト名
# secret 作成元のファイルを確認します
controlplane:~$ k create -f /opt/ks/secret-diver.yaml
secret/diver created
# creat コマンドで secret オブジェクトを作成します
controlplane:~$ k get secrets diver
NAME TYPE DATA AGE
diver Opaque 1 11s
# get で参照します
controlplane:~$ k get secrets diver -o yaml
apiVersion: v1
data:
hosts: MTI3LjAuMC4xCWxvY2FsaG9zdAoxMjcuMC4xLjEJaG9zdDAxCgojIFRoZSBmb2xsb3dpbmcgbGluZXMgYXJlIGRlc2lyYWJsZSBmb3IgSVB2NiBjYXBhYmxlIGhvc3RzCjo6MSAgICAgbG9jYWxob3N0IGlwNi1sb2NhbGhvc3QgaXA2LWxvb3BiYWNrCmZmMDI6OjEgaXA2LWFsbG5vZGVzCmZmMDI6OjIgaXA2LWFsbHJvdXRlcnMKMTI3LjAuMC4xIGhvc3QwMQoxMjcuMC4wLjEgaG9zdDAxCjEyNy4wLjAuMSBob3N0MDEKMTI3LjAuMC4xIGNvbnRyb2xwbGFuZQoxNzIuMTcuMC4zNSBub2RlMDEKMTcyLjE3LjAuMjMgY29udHJvbHBsYW5lCg==
kind: Secret
metadata:
creationTimestamp: "2025-04-15T02:25:18Z"
name: diver
namespace: default
resourceVersion: "7189"
uid: 3418e296-7ea8-4390-8f81-c60c8feba0c5
type: Opaque
# -oyaml で secret オブジェクトの中身を確認します
secret を pod にマウント
ここからは作成した secret を pod で利用する方法を確認します。まずは、volume として pod 内の特定パスにマウントします。
controlplane:~$ k run pod1 --image=nginx --dry-run=client -oyaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod1
name: pod1
spec:
containers:
- image: nginx
name: pod1
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
# ベースのyamlを作成する
controlplane:~$ cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod1
name: pod1
spec:
volumes:
- name: diver
secret:
secretName: diver # 事前に作成した secret を指定する
containers:
- image: nginx
name: pod1
volumeMounts:
- name: diver
readOnly: true # readOnlyであれば指定する
mountPath: "/etc/diver/" # secret をマウントするパスを指定する
resources: {} # マウントするhostsはテキストファイルなので上位のディレクトリまでを指定する
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
次に正しくマウントできているかを確認する。
controlplane:~$ k exec pod1 -- cat /etc/diver/hosts
127.0.0.1 localhost
127.0.1.1 host01
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.0.1 host01
127.0.0.1 host01
127.0.0.1 host01
127.0.0.1 controlplane
172.17.0.35 node01
172.17.0.23 controlplane
# マウントしたファイルを確認できます
続いて、secret を環境変数として代入します。
controlplane:~$ cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod1
name: pod1
spec:
volumes:
- name: diver
secret:
secretName: diver # 事前に作成した secret を指定する
containers:
- image: nginx
name: pod1
volumeMounts:
- name: diver
readOnly: true # readOnlyであれば指定する
mountPath: "/etc/diver/" # secret をマウントするパスを指定する
env:
- name: HOLY # 環境変数名を指定
valueFrom:
secretKeyRef:
name: holy # 参照先の secret 名を指定
key: creditcard # secret 内の key を指定
resources: {} # マウントするhostsはテキストファイルなので上位のディレクトリまでを指定する
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
# yaml 内容を確認します
controlplane:~$ k exec pod1 -- env |grep HOLY
HOLY=1111222233334444
# 正しく環境変数に設定されているか確認します
controlplane:~$ k get secrets holy -oyaml
apiVersion: v1
data:
creditcard: MTExMTIyMjIzMzMzNDQ0NA==
kind: Secret
metadata:
creationTimestamp: "2025-04-15T10:56:40Z"
name: holy
namespace: default
resourceVersion: "2475"
uid: b88654b7-b22e-403c-9740-5b4eec44c641
type: Opaque
# secret 内容を確認します
secret をデコード
デコードした secret の中身を確認します。
kubectl -n one get secret s1 -ojsonpath="{.data.data}" | base64 -d
kubectl -n one get secret s2 -ojsonpath="{.data.data}" | base64 -d
# スマートに jsonpath 指定で取得できます
controlplane:~$ k get -n one secrets s1 -oyaml |grep "data: " |awk '{ print $2 }' | base64 --decode >> /opt/ks/one
controlplane:~$ k get -n one secrets s2 -oyaml |grep "data: " |awk '{ print $2 }' | base64 --decode >> /opt/ks/one
# 実際に手を動かすとこんな感じです...
serviceaccount とは
サービスアカウントは人間以外のアカウントの一種で、KubernetesではKubernetesクラスタ内で個別のIDを提供しますAPIサーバーへの認証などのさまざまな場面で役立ちます。
serviceaccount 作成
create コマンドで作成します。
controlplane:~$ k create serviceaccount secret-manager
serviceaccount/secret-manager created
# 作成コマンドです
controlplane:~$ k get serviceaccounts -oyaml
apiVersion: v1
items:
- apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2025-03-22T19:51:55Z"
name: default # デフォルトの Serviceaccount です
namespace: default
resourceVersion: "426"
uid: 72c16a73-bb3a-4ddf-b484-8cd235d8a21a
- apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2025-04-15T11:15:56Z"
name: secret-manager # 作成した ServiceAccount です
namespace: default
resourceVersion: "2664"
uid: 6466b9af-d85e-48dd-a914-13a7db94c724
kind: List
metadata:
resourceVersion: ""
次に pod に作成した serviceaccount を設定します。
controlplane:~$ cat secret-manager.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: secret-manager
name: secret-manager
namespace: ns-secure
spec:
serviceAccountName: secret-manager # 作成した serviceaccount を指定します
volumes:
- name: secret-volume
secret:
secretName: sec-a2
containers:
- image: httpd:alpine
name: secret-manager
resources: {}
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/sec-a2"
env:
- name: SEC_A1
valueFrom:
secretKeyRef:
name: sec-a1
key: aaa
dnsPolicy: ClusterFirst
restartPolicy: Always
controlplane:~$ k apply -f secret-manager.yaml
pod/secret-manager created
serviceaccounttoken の自動マウントを制御
次に serviceaccouttoken の自動マウント動作を確認します。
controlplane:~$ cat /opt/ks/pod-one.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-one
namespace: one
spec:
serviceAccountName: custom
automountServiceAccountToken: false # serviceaccouttoken の自動マウント有無を指定します
containers:
- name: webserver
image: nginx:1.19.6-alpine
ports:
- containerPort: 80
controlplane:~$ k apply -f /opt/ks/pod-one.yaml
pod/pod-one created
# yaml を適用します
serviceaccounttoken のマウント状態を確認
serviceaccouttoken のマウント状態を確認します。
controlplane:~$ k exec -n one pod-one -- mount | grep serviceaccout
controlplane:~$ k exec -n one pod-one -- mount | cat /var/run/secrets/kubernetes.io/serviceaccount/token
cat: /var/run/secrets/kubernetes.io/serviceaccount/token: No such file or directory
# マウントを無効化しているため、マウントされていません
次に automoutServiceAccoutToken を true にして pod を作成します。
controlplane:~$ cat /opt/ks/pod-one.yaml |grep auto
automountServiceAccountToken: true
controlplane:~$ k replace -f /opt/ks/pod-one.yaml --force
pod "pod-one" deleted
pod/pod-one replaced
マウント状況を確認します
controlplane:~$ k exec -n one pod-one -- mount | grep serviceaccount
tmpfs on /run/secrets/kubernetes.io/serviceaccount type tmpfs (ro,relatime,size=1912956k,inode64,noswap)
controlplane:~$ kubectl -n one exec -it pod-one -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6InRaVDhLaEdBeGVWTHRXTkJJRUNDT1BGRmxkYmNzOFVCd2doYWpuSlNrODgifQ.--snip---
controlplane:~$
# マウントされていることを確認できます。
あとがき
アウトプットは良いですね!