Help us understand the problem. What is going on with this article?

KubernetesのToken Review API

More than 1 year has passed since last update.

KubernetesのAPIサーバと同じ認証を自前のpodとかでやりたいことがありませんか?

そんなときは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を使って検証しましょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした