Kubernetesは、クラスター内で実行されるクライアント、またはクラスターのコントロールプレーンと何らかの関係を持つクライアントが、APIサーバーに対して認証を行うために、2つの異なる方法を提供しています。
サービスアカウント は、Pod内で実行されるプロセスにアイデンティティを提供し、ServiceAccountオブジェクトにマッピングされます。 APIサーバーに対して認証を行う際、あなたは特定の ユーザー として自分自身を識別します。 Kubernetesはユーザーという概念を認識していますが、Kubernetes自体はUser APIを持っていません。
このタスクガイドでは、Kubernetes APIに存在するServiceAccountについて説明します。 このガイドでは、PodにServiceAccountを設定する方法をいくつか示します。
Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます:
PodがAPIサーバーに接続する際、Podは特定のServiceAccount(例: default)として認証を行います。
それぞれの名前空間には、常に少なくとも1つのServiceAccountが存在します。
すべてのKubernetes名前空間には、少なくとも1つのServiceAccountが含まれています。
それは、その名前空間のデフォルトのServiceAccountであり、defaultという名前が付けられています。
Podを作成する際にServiceAccountを指定しない場合、Kubernetesは自動的にその名前空間内に、defaultという名前のServiceAccountを割り当てます。
作成したPodの詳細を取得するには、たとえば下記を実行します:
kubectl get pods/<podname> -o yaml
出力には、spec.serviceAccountNameフィールドが表示されます。
Podを作成する際にこの値を指定しない場合、Kubernetesは自動的にこの値を設定します。
Pod内で実行されているアプリケーションは、自動的にマウントされたサービスアカウントの認証情報を使用して、Kubernetes APIにアクセスできます。 詳細については、クラスターへのアクセスを参照してください。
PodがServiceAccountとして認証を行う場合、そのアクセスレベルは、使用する認可プラグインとポリシーに依存します。
ファイナライザーが設定されている場合でも、Podが削除されるとAPI認証情報は自動的に取り消されます。
具体的には、Podに設定された.metadata.deletionTimestamp(削除タイムスタンプは通常、削除リクエストが受け入れられた時刻にPodの終了猶予期間を加えた時刻です)から60秒後にAPI認証情報が取り消されます。
kubeletが、ServiceAccountのAPI認証情報を自動的にマウントしないようにしたい場合、デフォルトの挙動をオプトアウトできます。
サービスアカウントに対して、automountServiceAccountToken: falseを設定することで、/var/run/secrets/kubernetes.io/serviceaccount/tokenへのAPI認証情報の自動マウントをオプトアウトできます。
例:
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
また、特定のPodに対してAPI認証情報の自動マウントをオプトアウトすることもできます:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
ServiceAccountとPodの.specの両方がautomountServiceAccountTokenの値を指定している場合、Podの仕様が優先されます。
すべての名前空間には、少なくとも1つのServiceAccountが存在します。
それは、defaultという名前のデフォルトのServiceAccountリソースです。
現在の名前空間内のすべてのServiceAccountリソースを次のコマンドで一覧表示できます:
kubectl get serviceaccounts
出力は以下のようになります:
NAME SECRETS AGE
default 1 1d
次のように、追加のServiceAccountオブジェクトを作成できます:
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
EOF
ServiceAccountオブジェクトの名前は、有効なDNSサブドメイン名である必要があります。
次のように、サービスアカウントオブジェクトの完全なダンプを取得する場合:
kubectl get serviceaccounts/build-robot -o yaml
出力は以下のようになります:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2019-06-16T00:12:34Z
name: build-robot
namespace: default
resourceVersion: "272500"
uid: 721ab723-13bc-11e5-aec2-42010af0021e
認可プラグインを使用して、サービスアカウントに権限を設定できます。
デフォルト以外のサービスアカウントを使用するには、Podのspec.serviceAccountNameフィールドを、使用したいServiceAccountの名前に設定します。
serviceAccountNameフィールドは、Podを作成する際、または新しいPodのテンプレート内でのみ設定できます。
既に存在するPodの.spec.serviceAccountNameフィールドは更新できません。
.spec.serviceAccountフィールドは、.spec.serviceAccountNameの非推奨のエイリアスです。
ワークロードリソースからこれらのフィールドを削除したい場合は、Podテンプレートで両方のフィールドを明示的に空に設定してください。上記の例でbuild-robot ServiceAccountを作成した場合、次のコマンドを実行してクリーンアップできます:
kubectl delete serviceaccount/build-robot
前述のように、「build-robot」という名前の既存のサービスアカウントがあるとします。
kubectlを使用して、そのServiceAccountの期限付きAPIトークンを取得できます:
kubectl create token build-robot
このコマンドの出力は、そのServiceAccountとして認証するために使用できるトークンです。
kubectl create tokenの--durationコマンドライン引数を使用して、特定のトークン期間を要求できます(発行されるトークンの実際の期間は短くなる場合や、長くなる場合もあります)。
Kubernetes v1.33 [stable](enabled by default)kubectl v1.31以降を使用すると、ノードに直接バインドされたサービスアカウントトークンを作成できます:
kubectl create token build-robot --bound-object-kind Node --bound-object-name node-001 --bound-object-uid 123...456
トークンは、有効期限が切れるか、関連するノードまたはサービスアカウントが削除されるまで有効です。
Kubernetes v1.22以前のバージョンでは、Kubernetes APIにアクセスするための長期的な認証情報が自動的に作成されていました。 この古いメカニズムは、実行中のPodにマウントされるトークンSecretの作成に基づいていました。 Kubernetes v1.35を含む最近のバージョンでは、API認証情報はTokenRequest APIを使用して直接取得され、projected volumeを使用してPodにマウントされます。 この方法で取得されたトークンには有効期限があり、マウント先のPodが削除されると自動的に無効になります。
サービスアカウント用のトークンSecretを手動で作成することも可能です。 例えば、有効期限のないトークンが必要な場合などです。 ただし、APIにアクセスするためのトークンを取得するには、TokenRequestサブリソースを使用することを推奨します。
ServiceAccount用のAPIトークンを取得したい場合は、特別なアノテーションkubernetes.io/service-account.nameを持つ新しいSecretを作成します。
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: build-robot-secret
annotations:
kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
EOF
Secretを表示するには、次のコマンドを使用します:
kubectl get secret/build-robot-secret -o yaml
Secretに「build-robot」ServiceAccount用のAPIトークンが含まれていることが確認できます。
設定したアノテーションにより、コントロールプレーンはそのServiceAccount用のトークンを自動的に生成し、関連するSecretに保存します。 また、コントロールプレーンは削除されたServiceAccount用のトークンをクリーンアップします。
kubectl describe secrets/build-robot-secret
出力は以下のようになります:
Name: build-robot-secret
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: build-robot
kubernetes.io/service-account.uid: da68f9c6-9d26-11e7-b84e-002dc52800da
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1338 bytes
namespace: 7 bytes
token: ...
tokenの内容はここでは省略されています。
ターミナルやコンピューターの画面が覗き見される可能性がある場所で、kubernetes.io/service-account-token Secretの内容を表示しないよう注意してください。
関連するSecretを持つServiceAccountを削除すると、KubernetesコントロールプレーンはそのSecretから長期的なトークンを自動的にクリーンアップします。
ServiceAccountを表示するには、次のコマンドを使用します:
kubectl get serviceaccount build-robot -o yaml
ServiceAccount APIオブジェクトの.secretsフィールドにbuild-robot-secret Secretは表示されません。
このフィールドには自動生成されたSecretのみが入力されるためです。
まず、imagePullSecretを作成します。 次に、作成されたことを確認します。 以下は、その例です:
PodでのImagePullSecretの指定で説明されているように、imagePullSecretを作成します。
kubectl create secret docker-registry myregistrykey --docker-server=<レジストリ名> \
--docker-username=DUMMY_USERNAME --docker-password=DUMMY_DOCKER_PASSWORD \
--docker-email=DUMMY_DOCKER_EMAIL
作成されたことを確認します。
kubectl get secrets myregistrykey
出力は以下のようになります:
NAME TYPE DATA AGE
myregistrykey kubernetes.io/.dockerconfigjson 1 1d
次に、名前空間のデフォルトのサービスアカウントを変更して、このSecretをimagePullSecretとして使用するようにします。
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'
オブジェクトを手動で編集することでも同じ結果を得られます:
kubectl edit serviceaccount/default
sa.yamlファイルの出力は以下のようになります:
使用しているテキストエディターが開き、以下のような設定が表示されます:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2021-07-07T22:02:39Z
name: default
namespace: default
resourceVersion: "243024"
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
エディターを使用して、resourceVersionキーが記述されている行を削除し、imagePullSecrets:の行を追加して保存します。
uidの値は変更しないでおきます。
これらの変更を行うと、編集後のServiceAccountは以下のようになります:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2021-07-07T22:02:39Z
name: default
namespace: default
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
imagePullSecrets:
- name: myregistrykey
現在の名前空間に、デフォルトのServiceAccountを使用して新しいPodが作成されると、新しいPodのspec.imagePullSecretsフィールドが自動的に設定されます:
kubectl run nginx --image=<レジストリ名>/nginx --restart=Never
kubectl get pod nginx -o=jsonpath='{.spec.imagePullSecrets[0].name}{"\n"}'
出力は以下のようになります:
myregistrykey
Kubernetes v1.20 [stable]
トークンリクエスト投影を有効化して使用するには、kube-apiserverに以下の各コマンドライン引数を指定する必要があります:
--service-account-issuer--service-account-issuer引数は複数回指定でき、発行者をダウンタイムなしで変更するのに役立ちます。
このフラグを複数回指定した場合、最初のものがトークンの生成に使用され、すべてが受け入れ可能な発行者の判定に使用されます。
--service-account-issuerを複数回指定するには、Kubernetes v1.22以降を実行する必要があります。--service-account-key-file--service-account-signing-key-file--api-audiences(省略可能)api-audiencesを複数回指定した場合、指定したオーディエンスのいずれかに対応するトークンは、Kubernetes APIサーバーによって有効と見なされます。
--service-account-issuerコマンドライン引数を指定しても--api-audiencesを設定しない場合、コントロールプレーンはデフォルトで発行者URLのみを含むオーディエンスリストを使用します。kubeletも、ServiceAccountトークンをPodに投影できます。 トークンの望ましいプロパティ(オーディエンスや有効期間など)を指定できます。 これらのプロパティは、デフォルトのServiceAccountトークンでは設定 できません。 また、PodまたはServiceAccountのいずれかが削除されると、トークンはAPIに対して無効になります。
この挙動は、ServiceAccountTokenと呼ばれる投影ボリュームタイプを使用してPodのspecで設定できます。
この投影ボリュームのトークンはJSON Web Token(JWT)です。 このトークンのJSONペイロードは明確に定義されたスキーマに従い、以下はPodにバインドされたトークンのペイロードの例です:
{
"aud": [ # リクエストされたオーディエンス、または明示的にリクエストされない場合はAPIサーバーのデフォルトオーディエンスと一致
"https://kubernetes.default.svc"
],
"exp": 1731613413,
"iat": 1700077413,
"iss": "https://kubernetes.default.svc", # --service-account-issuerフラグに渡された最初の値と一致
"jti": "ea28ed49-2e11-4280-9ec5-bc3d1d84661a",
"kubernetes.io": {
"namespace": "kube-system",
"node": {
"name": "127.0.0.1",
"uid": "58456cb0-dd00-45ed-b797-5578fdceaced"
},
"pod": {
"name": "coredns-69cbfb9798-jv9gn",
"uid": "778a530c-b3f4-47c0-9cd5-ab018fb64f33"
},
"serviceaccount": {
"name": "coredns",
"uid": "a087d5a0-e1dd-43ec-93ac-f13d89cd13af"
},
"warnafter": 1700081020
},
"nbf": 1700077413,
"sub": "system:serviceaccount:kube-system:coredns"
}
オーディエンスがvaultで、有効期間が2時間のトークンをPodに提供するには、以下のようなPodマニフェストを定義します:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: vault-token
serviceAccountName: build-robot
volumes:
- name: vault-token
projected:
sources:
- serviceAccountToken:
path: vault-token
expirationSeconds: 7200
audience: vault
Podを作成します:
kubectl create -f https://k8s.io/examples/pods/pod-projected-svc-token.yaml
kubeletは、Podに代わってトークンをリクエストして保存し、設定可能なファイルパスでPodがトークンを利用できるようにします。 また、トークンの有効期限が近づくと更新します。 kubeletは、トークンの全生存時間(TTL)の80%を経過した場合、または24時間を経過した場合に、積極的にトークンのローテーションをリクエストします。
トークンがローテーションされた際にトークンを再読み込みするのは、アプリケーション側の責任です。 多くの場合、実際の有効期限を追跡しなくても、定期的に(例えば5分ごとに)トークンを読み込むだけで十分です。
Kubernetes v1.21 [stable]
クラスター内のServiceAccountに対してトークン投影を有効にしている場合、ディスカバリ機能も利用できます。 Kubernetesは、クライアントが アイデンティティプロバイダー として連携できる方法を提供し、1つ以上の外部システムが リライングパーティ として機能できます。
発行者URLはOIDC Discovery仕様に準拠している必要があります。
実際には、これはhttpsスキームを使用する必要があり、{service-account-issuer}/.well-known/openid-configurationでOpenIDプロバイダー設定を提供する必要があることを意味します。
URLが準拠していない場合、ServiceAccount発行者のディスカバリエンドポイントは登録されず、アクセスできません。
有効にすると、Kubernetes APIサーバーはHTTP経由でOpenIDプロバイダー設定ドキュメントを公開します。
設定ドキュメントは/.well-known/openid-configurationで公開されます。
OpenIDプロバイダー設定は、ディスカバリドキュメント と呼ばれることもあります。
Kubernetes APIサーバーは、関連するJSON Web Key Set(JWKS)もHTTP経由で/openid/v1/jwksで公開します。
/.well-known/openid-configurationや/openid/v1/jwksで提供される応答は、OIDC互換となるように設計されていますが、厳密にはOIDC準拠ではありません。
これらのドキュメントには、Kubernetesサービスアカウントトークンの検証を実行するために必要なパラメーターのみが含まれています。RBACを使用するクラスターには、system:service-account-issuer-discoveryというデフォルトのClusterRoleが含まれています。
デフォルトのClusterRoleBindingは、このロールをsystem:serviceaccountsグループに割り当てます。
すべてのServiceAccountは暗黙的にこのグループに属しています。
これにより、クラスター上で実行されているPodは、マウントされたサービスアカウントトークンを介してサービスアカウントディスカバリドキュメントにアクセスできます。
管理者は、セキュリティ要件や連携する予定の外部システムに応じて、さらにsystem:authenticatedまたはsystem:unauthenticatedにロールをバインドすることもできます。
JWKS応答には、リライングパーティがKubernetesサービスアカウントトークンを検証するために使用できる公開鍵が含まれています。
リライングパーティは、まずOpenIDプロバイダー設定をクエリし、応答内のjwks_uriフィールドを使用してJWKSを見つけます。
多くの場合、Kubernetes APIサーバーはパブリックインターネット上では利用できませんが、APIサーバーからのキャッシュされた応答を提供するパブリックエンドポイントをユーザーまたはサービスプロバイダーが利用可能にすることができます。
これらの場合、APIサーバーに--service-account-jwks-uriフラグを渡すことで、OpenIDプロバイダー設定内のjwks_uriをオーバーライドして、APIサーバーのアドレスではなくパブリックエンドポイントを指すようにすることができます。
発行者URLと同様に、JWKS URIもhttpsスキームを使用する必要があります。
以下も参照してください: