KubernetesのAPIサーバと同じ認証を自前のpodとかでやりたいことがありませんか? 例えばAPIサーバにアクセスするためのIDトークンで認証しメールアドレスを使いたいとかサービスアカウントで認証したいとか。
そんなときはTokenReview APIを使ってみるといいかもしれません。
これはKubernetesのAPIサーバに対してBearerトークンをリクエストパラメータとして渡すと、APIサーバが有効かどうかを判断して結果を返してくれるAPIです。例えばServiceAccountのトークンや、OIDCを有効にしている場合にはID Tokenなんかを渡すことができます。
v1.7以降ではTokenReview APIには以下のURIでアクセスできます。
https://${API_SERVER_ADDR}/apis/authentication.k8s.io/v1/tokenreviews
リクエストパラメータは以下のようなJSONデータです。
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "TokenReview",
"spec": {
"token": <USER_TOKEN>
}
}
これをTokenReviewAPIにPOSTしてやるとレスポンスが返ってきます。
$ curl -H "Content-Type: application/json" \
-H 'Authorization: Bearer ${SYTEM_TOKEN}' \
-d '{"apiVersion": "authentication.k8s.io/v1","kind": "TokenReview","spec": {"token": <USER_TOKEN>}}'
https://${API_SERVER_ADDR}/apis/authentication.k8s.io/v1/tokenreviews \
例えばkube-apiserverに対してOIDCの認証設定かつusernameのフィールドとしてemailを使う設定をしている場合などは、TokenReview APIにID Tokenを渡すと、認証した結果のusernameの値としてemailアドレスが入っています。
{
"kind": "TokenReview",
"apiVersion": "authentication.k8s.io/v1",
"metadata": {
"creationTimestamp": null
},
"spec": {
"token": <USER_TOKEN>
},
"status": {
"authenticated": true,
"user": {
"username": "foo@example.org"
"groups": [
"system:authenticated"
]
}
}
}
ServiceAccountトークンを渡した場合はusernameが以下のようなフォーマットの文字列になります。
system:serviceaccount:<namespace>:<name>
Tokenが有効でない場合や期限が切れている場合などは status.authenticated
の値が false
になります。
{
"kind": "TokenReview",
"apiVersion": "authentication.k8s.io/v1",
"metadata": {
"creationTimestamp": null
},
"spec": {
"token": <USER_TOKEN>
},
"status": {
"authenticated": false,
}
}
このAPIを呼び出すには system:auth-delegator
の権限が必要なので、TokenReview APIを呼びすアカウントに対してClusterRoleBindingまたはRoleBindingで権限を付与してあげてください。
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: sample-ns:system:auth-delegator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: default
namespace: sample-ns
さらにGoLangのコードからこれらを呼び出す場合にはvaultのKubernetes Auth Backend プラグインのコードを参考にするとよいでしょう。client-goのパッケージを使ってTokenReview APIを呼び出しています。
https://github.com/hashicorp/vault-plugin-auth-kubernetes
最後にひとつ注意すべき点を記載しておきます。
今回TokenReview APIで扱っているID TokenやServiceAccount TokenはいずれもJWT形式なので署名を検証するための公開鍵さえあれば自前で検証できてしまいますが、TokenのRevokeや公開鍵ペアのローテーションが発生した場合の考慮を十分にしておく必要があります。
ID Tokenの場合にはトークンのclaimとしてexpなどが含まれているため、Revokeやキーのローテーションが発生したとしても最悪の場合でもexpの値である期限までしか使えませんが、ServiceAccount Tokenは期限を持っていないためRevokeやローテーションに関係なく永遠に使い続けられてしまいとても危険な状態になります。
よほど問題がない限りは正しくTokenReview APIを使って検証しましょう。