SSO でクラスターにログインする
Kubernetes にはユーザーデータベースがありません。User という object も、ユーザーを作成するコマンドもありません。API server が知っているのは、Identity Provider(IdP)がすでに保証している identity を検証する方法だけです。
認証フロー: あなた(kubectl + kubelogin)がログイン → IdP(Keycloak/Azure AD/Okta)が ID token を返す → その token を API server に直接送信 → API server が IdP の JWKS で署名を検証 → Kubernetes RBAC が権限を決定します。
token はあなたから API server へ直接送られます — IdP はリクエストの経路には含まれません。IdP が一時的に停止しても、キャッシュ済みの token は有効期限まで使え、クラスターは通常どおり動作します。
ログインに成功しても、何かをする権限があるとは限りません。認証されたが RoleBinding を持たないユーザーは、kubectl get pods のようなコマンドで 403 Forbidden を受け取ります。これは設計どおりの動作であり、構成ミスではありません。
開始する前に
| 項目 | 要件 |
|---|---|
| クラスター | 管理者が OIDC 認証をすでに有効化していること — クラスターの OIDC 認証を構成する を参照。 |
| ツール | 自分の端末に kubectl と kubelogin がインストールされていること。 |
| ネットワーク | 自分の端末からクラスターの API server と IdP の両方に到達できること。 |
| HTTPS | IdP が有効な証明書を使用していること — 社内 CA を使用している場合は、その CA を端末に取り込む必要があります。 |
| アカウント | IdP 上のユーザー名/パスワードがあり、適切な group に追加されていること。 |
さらに、クラスター管理者から次の 4 つの情報を受け取る必要があります。これらがすべて揃わないと kubeconfig を作成できません。
| 情報 | 用途 |
|---|---|
| API server URL | kubeconfig の server フィールド。 |
| クラスターの CA certificate | certificate-authority-data フィールド。 |
| Issuer URL(IdP) | 管理者が Portal で OIDC を構成したときに入力した Issuer URL と同じ値。 |
| Client ID | 管理者が Portal で OIDC を構成したときに入力した Client ID と同じ値。 |
kubelogin をインストールする
ステップ 1 — krew(kubectl のプラグインマネージャー)をインストールする
公式の krew インストールガイド(krew.sigs.k8s.io)を参照してください。
ステップ 2 — PATH に追加する
echo 'export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Using zsh: replace ~/.bashrc with ~/.zshrc
# Confirm
kubectl krew version
~/.bashrc に設定した PATH は、対話的なシェルにのみ適用されます。ssh host 'kubectl ...' のような実行方法やスクリプト内では、このファイルは読み込まれません。そのような場合は、次のように明示的に追加してください: export PATH="$HOME/.krew/bin:$PATH"; kubectl get nodes。
ステップ 3 — oidc-login プラグインをインストールする
kubectl krew install oidc-login
# Upgrade later
kubectl krew upgrade oidc-login
# See installed version
kubectl krew list
インストールを確認する
# 1. Does the binary run?
kubectl oidc-login --version
# kubelogin version v1.36.4
# 2. Does kubectl recognize the plugin?
kubectl plugin list
# /root/.krew/bin/kubectl-oidc_login
# 3. Can you reach the IdP? (replace with your real issuer URL)
curl -sI https://sso.example.com/realms/kubernetes/.well-known/openid-configuration | head -1
# HTTP/2 200
| インストール時のエラー | 原因 | 対処方法 |
|---|---|---|
unknown command "krew" | ステップ 1 を実行していない、またはステップ 2 を省略した | ~/.krew/bin を PATH に追加し、source ~/.bashrc を実行する |
unknown command "oidc-login" | プラグインが未インストール、または PATH に ~/.krew/bin がない | kubectl krew list で確認し、ステップ 2 を見直す |
| 手動実行はできるが SSH 経由だとできない | 非対話的シェルでは ~/.bashrc が読み込まれない | コマンドの先頭に export PATH="$HOME/.krew/bin:$PATH" を追加する |
| kubelogin のバージョンが古すぎる | 長期間更新していない | kubectl krew upgrade oidc-login |
ユーザー用の kubeconfig を作成する
OIDC の kubeconfig にはパスワードや token は含まれません。kubelogin をどう呼び出して token を取得するかを記述しているだけです。そのため、1 つのファイルをチーム全員に配布でき、それぞれが自分のアカウントでログインして、自分に対応する権限を得られます。
サンプルファイル(全体)
apiVersion: v1
kind: Config
current-context: my-cluster-sso
clusters:
- name: my-cluster
cluster:
server: https://api.my-cluster.example.com
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0t...
contexts:
- name: my-cluster-sso
context:
cluster: my-cluster
user: sso-user
namespace: payment
users:
- name: sso-user
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: kubectl
args:
- oidc-login
- get-token
- --oidc-issuer-url=https://sso.example.com/realms/kubernetes
- --oidc-client-id=kubernetes
- --oidc-extra-scope=email
- --oidc-extra-scope=profile
# Machine with no browser: add the 2 lines below
# - --grant-type=device-code
# - --skip-open-browser
interactiveMode: IfAvailable
installHint: |
kubelogin isn't installed. Install it with:
kubectl krew install oidc-login
--oidc-issuer-url と --oidc-client-id は、クラスター管理者が Portal で OIDC を構成したときに設定した Issuer URL と Client ID(クラスターの OIDC 認証を構成する を参照)と同じ値です — この 2 つの値を、クラスター管理者に確認してください。
ファイル構造 — 3 つのブロックとその関係
clusters ──┐ which cluster (address + CA)
├── contexts ── links a cluster to a user, plus a default namespace
users ──┘ how to log in
current-context が、現在使用する context を指定します。1 つのファイルに複数のクラスターと複数の context を含めることができ、kubectl config use-context で切り替えられます。
clusters ブロック:
| フィールド | 意味 |
|---|---|
server | API server の HTTPS アドレス。管理者に確認してください。 |
certificate-authority-data | クラスターの CA(base64 形式)。API server の証明書を検証するために使用します — 機密情報ではありません。 |
certificate-authority | 上記フィールドの代わりに、.crt ファイルのパスを指定します。どちらか一方のみ使用します。 |
insecure-skip-tls-verify | 使用は避けてください。証明書の検証をスキップします — 使い捨ての lab 環境でのみ使用します。 |
contexts ブロック:
| フィールド | 意味 |
|---|---|
cluster | クラスター名。clusters 内のエントリと一致させる必要があります。 |
user | ユーザー名。users 内のエントリと一致させる必要があります。 |
namespace | -n を指定しない場合に使われる既定の namespace。 |
exec ブロックの各パラメーターの説明
この部分が、ログイン方法を決定します。kubectl は command を args 付きで実行し、その出力から token を読み取ります。
exec のフィールド
| フィールド | 値 | 意味 |
|---|---|---|
apiVersion | client.authentication.k8s.io/v1beta1 | exec credential プロトコルのバージョン |
command | kubectl | 呼び出されるコマンド(kubelogin はプラグインのため) |
args | リスト | コマンドに渡す引数 |
interactiveMode | IfAvailable | terminal を占有してよいタイミング |
installHint | テキスト | kubelogin が未インストールの場合に表示されるメッセージ |
必須の 2 つの引数
| 引数 | 意味 |
|---|---|
oidc-login get-token | プラグイン名 + サブコマンド。先頭に、この順序で指定する必要があります |
--oidc-issuer-url | IdP のアドレス — クラスターの構成と 1 文字も違わず 一致する必要があります |
--oidc-client-id | IdP に登録したアプリケーションの識別子。API server が検証する aud にもなります |
よく使う任意の引数
| 引数 | 必要になる場合 |
|---|---|
--oidc-client-secret | client が confidential の場合のみ |
--oidc-extra-scope | 追加の scope をリクエストする場合。通常は email と profile |
--grant-type | auto(既定)、authcode、device-code、password |
--skip-open-browser | ブラウザがない端末の場合 |
--certificate-authority | IdP 用の CA(クラスターの CA とは異なります) |
--force-refresh | キャッシュを無視して新しい token を取得する — group 変更直後に便利 |
-v=1 … -v=5 | ログレベル。トラブルシューティングには -v=5 を使用 |
--oidc-extra-scope=groups は追加しないでください。group の情報は IdP 管理者が構成する protocol mapper から来るもので、scope から来るものではありません。IdP が定義していない groups scope をリクエストすると invalid_scope エラーになります。
token キャッシュの仕組み
初回実行時、kubelogin は token を ~/.kube/cache/oidc-login に保存します。以降の実行ではキャッシュを読み取り、自動的に refresh し、refresh token の有効期限が切れたときのみ再ログインを求めます。
# Clear the cache when you need to force a re-login (required after a group change)
rm -rf ~/.kube/cache/oidc-login # Linux/macOS
Remove-Item -Recurse -Force "$env:USERPROFILE\.kube\cache\oidc-login" # Windows
ログイン成功を確認する
kubectl auth whoami
ATTRIBUTE VALUE
Username oidc:nguyenvana
Groups [oidc:team-payment system:authenticated]
正しい名前と group が表示されれば、認証は正しく機能しています。その後 403 が発生する場合は authorization の問題です。Kubernetes 権限を割り当てる を参照してください。
ブラウザがない端末の場合
jump host、server、container など、ブラウザを開けない環境です。既定の kubeconfig をそのまま使うと、処理が止まり最終的に context deadline exceeded になります。
-
Device code(推奨):
argsに次の 2 行を追加します。- --grant-type=device-code- --skip-open-browserterminal に、コードが入力済みのリンクが表示されます。それをスマートフォンや別の端末で開いてログインし、terminal に戻って数秒待てば完了します。コードの有効期限は 10 分です。
-
SSH port forwarding: kubeconfig は既定のままにし、
ssh -L 8000:localhost:8000 -L 18000:localhost:18000 user@jumphostで接続してから、jump host 上で通常どおりkubectlを実行します。 -
Authcode keyboard:
--grant-type=authcode-keyboard— URL を開いてログインし、返されたコードを terminal に貼り付けます。 -
Password grant:
--grant-type=password --username=...— アカウントで MFA が有効な場合は使用できません。非推奨であり、簡易なテスト時のみ使用してください。
CI/CD には OIDC ログインを使わず、ServiceAccount token を使用してください(use case 7 を参照)。
Kubernetes 権限を割り当てる
マッピングルール
クラスター管理者が構成した prefix(Portal で OIDC を構成する際に Advanced で入力した Username Prefix / Groups Prefix)が、IdP から来るすべての identity に付加されます。
| IdP 上 | token 内の claim | RBAC で使う名前 |
|---|---|---|
ユーザー nguyenvana | preferred_username | oidc:nguyenvana |
Group k8s-admins | groups[] | oidc:k8s-admins |
prefix が何か分からない場合は kubectl auth whoami を実行してください — 表示される値が、RBAC で使うべき名前そのものです。
権限は必ず User ではなく Group に割り当ててください。kind: User に割り当てると、チームへの加入・離脱があるたびに各クラスターの RBAC を修正する必要があります。kind: Group に割り当てれば、IdP 上でメンバーを追加・削除するだけで済みます。唯一の例外は break-glass アカウントです。
組み込みの 4 つの ClusterRole
| ClusterRole | 権限 | 用途 |
|---|---|---|
cluster-admin | すべての namespace に対する full access | インフラ管理者 |
admin | 1 つの namespace 内での full access(RoleBinding の作成を含む) | チームリーダー |
edit | リソースの編集は可能だが RBAC 自体は編集不可 | 開発者 |
view | 読み取り専用。Secret は除外 | QA、監視担当者 |
ClusterRoleBinding はクラスター全体への権限を付与し、RoleBinding は 1 つの namespace に権限を限定します(ClusterRole を参照することもできます)。
よくある 8 つのユースケース
クラスター全体の管理者
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: sso-cluster-admins
subjects:
- kind: Group
name: "oidc:k8s-admins"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
クラスター全体の読み取り専用アクセス
use case 1 と同様ですが、roleRef.name: view を使用します。view ClusterRole は Secret の読み取りを意図的に除外しています。
チームが自分の namespace を所有する
チームリーダーには admin、開発者には edit を割り当てます。
# Team lead
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: payment-leads
namespace: payment
subjects:
- kind: Group
name: "oidc:team-payment-lead"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
---
# Developers
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: payment-devs
namespace: payment
subjects:
- kind: Group
name: "oidc:team-payment"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: edit
apiGroup: rbac.authorization.k8s.io
namespace 一覧の表示を許可する
Namespace はクラスタースコープのリソースのため、RoleBinding だけでは不十分です。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-lister
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: all-users-list-namespaces
subjects:
- kind: Group
name: "system:authenticated"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: namespace-lister
apiGroup: rbac.authorization.k8s.io
これにより、ログイン済みの全ユーザーにすべての namespace 名が公開されます。
複数チームでクラスターを共有し、クォータを設ける
RBAC だけでは「どれだけ使えるか」は制限できません — ResourceQuota を組み合わせます。
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: payment
spec:
hard:
requests.cpu: "40"
requests.memory: 160Gi
requests.nvidia.com/gpu: "8"
persistentvolumeclaims: "20"
count/deployments.apps: "50"
GPU 対応のクラスターでは GPU quota が必須です — 設定しないと、1 つの Deployment だけで 1 チームがすべての GPU を占有できてしまいます。
1 種類のリソースに対する狭い権限
例: on-call 担当者が log の確認や pod の再起動はできるが、Deployment の編集や Secret の読み取りはできない場合。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: oncall-responder
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "events"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["delete"] # restart = delete the pod, the ReplicaSet recreates it
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets"]
verbs: ["get", "list"]
CI/CD では SSO ではなく ServiceAccount を使う
kubectl -n payment create serviceaccount ci-deployer
kubectl -n payment create rolebinding ci-deployer \
--clusterrole=edit --serviceaccount=payment:ci-deployer
kubectl -n payment create token ci-deployer --duration=24h
Kubernetes 1.24 以降、ServiceAccount は永続的な token を含む Secret を自動生成しなくなりました — create token で生成する token には有効期限があり、より安全です。
人事異動があった場合のアクセス取り消し
| 状況 | 対応 | 反映されるタイミング |
|---|---|---|
| チームの異動 | IdP 上の group を変更する | 次回の token refresh 時 |
| 退職 | IdP 上のアカウントを無効化する | token の lifetime を上限として |
| 即時に遮断する必要がある場合 | アカウントを無効化し、かつ session を削除する | 新しい session からは即時に反映 |
発行済みの token は取り消せません — bearer token の本質的な制約です。リスクの発生し得る期間は、token の有効期間と同じです。機密性の高いシステムでは、5〜10 分程度に設定することを推奨します。
トラブルシューティング
401 と 403 の違い — 最初に必ず確認すること
| コード | 意味 | 問題のある層 | 対応者 |
|---|---|---|---|
| 401 | Unauthorized | 認証 — token が受け付けられない | クラスター管理者 / IdP |
| 403 | Forbidden | 権限 — token は有効だが権限が不足 | クラスター管理者(RBAC) |
401 が発生している間は RBAC を修正しないでください。401 は、API server がそもそもあなたの identity を認識していないことを意味します — RoleBinding をいくつ追加しても解決しません。
よくあるエラーの一覧
| 症状 | 原因 | 対処方法 |
|---|---|---|
ログインは成功するのに 401 になる | kubeconfig の Issuer URL がクラスターの構成と一致していない、またはクラスターで OIDC が有効になっていない | issuer URL を 1 文字ずつ比較する。クラスター管理者に連絡する |
403 になるが、whoami の名前は正しい | RoleBinding がまだない、または RBAC 上の group 名が一致していない | kubectl auth whoami の出力をクラスター管理者に送る |
| whoami で Groups が空になる | IdP が group を token に含める mapper を構成していない | IdP 管理者に連絡する |
context deadline exceeded | kubelogin が非対話的な実行でブラウザを待っている | --grant-type=device-code を使用する |
invalid_scope | IdP が定義していない scope をリクエストしている | --oidc-extra-scope=groups を削除する |
| whoami で想定外の identity が表示される | KUBECONFIG 変数が切り替わっていない | $env:KUBECONFIG を使う、または --kubeconfig を渡す |
| group を変更しても権限が変わらない | 古い token がまだキャッシュに残っている | ~/.kube/cache/oidc-login を削除する |
invalid_grant | パスワードが間違っている、またはアカウントが無効化されている | IdP 上のアカウントを確認する |
x509: certificate signed by unknown authority | IdP が信頼されていない社内 CA を使用している | --certificate-authority=/path/to/ca.crt を追加する |
address already in use | ポート 8000 がすでに使用されている | --listen-address=127.0.0.1:8100 を追加し、新しい redirect URI を登録する |
Missing parameter: code_challenge_method | IdP が device endpoint で PKCE を必須にしている | 管理者に PKCE の要件を緩めてもらう、または SSH port forwarding を使用する |
could not open the browser: exit status 3 | エラーではありません — 端末にブラウザがないだけです | 下に表示される "Please visit..." の行を探し、そのリンクを開いてください |
3 つの診断コマンド(順番どおりに)
# 1. Who does the API server think I am?
kubectl auth whoami
# 2. Can I do this specific thing?
kubectl auth can-i create deployments -n payment
# 3. See everything I can do in one namespace
kubectl auth can-i --list -n payment
ログイン処理の詳細を確認する
kubectl oidc-login get-token -v=5 \
--oidc-issuer-url=https://sso.example.com/realms/kubernetes \
--oidc-client-id=kubernetes
token を取得できれば IdP 側は問題なく、問題はクラスター側にあります。取得できない場合は、IdP 側またはそこまでのネットワークに問題があります。
セキュリティチェックリスト
- token を含む kubeconfig を共有しない。 OIDC の kubeconfig は機密情報を含まないため、チーム全体に配布しても安全です — ただし、
token:やclient-key-data:フィールドがすでに含まれているファイルは絶対に配布しないでください。 insecure-skip-tls-verifyを使わない。 使い捨ての lab 環境以外では使用しないでください。- クラスター管理権限を持つアカウントには MFA を有効化する。
- 共有端末から離れる際は token キャッシュを削除する:
rm -rf ~/.kube/cache/oidc-login。 - 誤った namespace での操作を防ぐため、context に 既定の namespace を設定する。
viewから始める。 具体的な必要がある場合にのみ権限を上げてください。利便性のためにcluster-adminを要求しないでください。- 権限は group 単位で割り当て、user 単位では割り当てない。 唯一の例外は break-glass アカウントです。
- break-glass 用の kubeconfig を保管する。 IdP が停止していても、対応のためにクラスターへアクセスできる手段が必要です。安全な場所に保管してください。
- 定期的に見直す。 四半期ごとに、IdP 上の group メンバーと実際のチーム名簿を照合してください。
このガイドは、Portal を通じて OIDC 認証がすでに有効化されているクラスター(クラスターの OIDC 認証を構成する を参照)、および Linux 上で krew 経由で kubelogin をインストールしている環境を前提としています。Identity Provider 自体の構成やクラスターでの OIDC 有効化は、クラスター管理者の責任範囲です — 開始する前に に記載した 4 つの情報については、管理者に問い合わせてください。