TT Lab
はじめる
学ぶ 学習パス コース

KCSA — Kubernetesセキュリティアソシエイト

識別情報・受信者・権限は別々の問い

TT Labで続きを見る

一言でいうと

トークンが誰を表すのか、誰に送れるのか、どんなことを許可されているのかは、それぞれ別の問いです。 デコードの結果や、管理者による代理リクエストだけでは、3つの問いのすべてには答えられません。

なぜ必要なのか

事故の例です。レポートサービスに使っていたトークンをKubernetes APIに送ると、401が返ってきました。 チームメンバーは、ロールに権限が足りないからcluster-adminを付けようと言います。別のメンバーは、トークンの 有効期限が明日なのだからサーバーが間違っていると言います。2人とも、まだ原因を確認していません。 受信者の違うトークンであれば、権限を増やしても解決せず、不要な権限だけが残ります。

この単元の個人VMには、同じ名前のreaderアカウントが2つのネームスペースにあります。 各アカウントは、自分のネームスペースのlesson-policy ConfigMap 1つだけを読めます。 データはtraining-onlyという合成文字列です。機微なシークレットがなくても、認証と認可の 違いを再現できるので、実際のサービストークンを持ち込んで練習する理由はありません。

どう動くのか

発行・検証・使用を別々に観測する

TokenRequestは、サービスアカウントの認証情報の発行を受けるためのリクエストです。リクエストには、audienceと 希望する有効期間、必要ならバインドするオブジェクトの名前とUIDを入れます。レスポンスの実際の有効期限を 確認する必要があり、リクエストした数字が常にそのまま適用されると仮定してはいけません。 今回は、管理者が教育用アカウントのトークンを発行します。この管理者の発行権限と、 発行されたトークンの主体のConfigMapの読み取り権限は、別のものです。

JWTの中央の部分をbase64urlでデコードすると、sub・aud・expのようなクレームを読めます。 しかし、署名まで検証したわけではありません。紙に書かれた社員番号を読むことと、発行機関に 身分証の真偽を確認することは違います。トークンの内容を読んだだけで、検証が完了したとは書きません。

TokenReviewは、トークンの認証結果を尋ねるときに使います。今回のヘルパーは、管理者のリクエストで その検査を実行しますが、トークンの原文の代わりに、認証の可否、audience、username、UIDだけを表示します。 この結果がtrueでも、そのユーザーのConfigMapの取得を許可したという意味ではありません。 実際の読み取りリクエストを別に送って初めて、ロールとバインディングの結果まで確認できます。

リクエストに別の身分証を混ぜない

管理者のkubeconfigを使うkubectlにオプションを1つだけ追加して、サービスアカウントの行動だと 呼ぶと、実験があいまいになります。今回のGETクライアントは、管理者のクライアント証明書を使わず、 Authorizationのbearerトークンだけを使います。サーバーCAの検証は維持し、リダイレクトとproxyは 使いません。どのアドレスにどの認証情報が送られたかが、実験の一部です。

管理者に許可された--asによる代理リクエストは、RBACを点検するのに役立ちます。しかし、そのリクエストには、 検査しようとしている古いトークンの署名・audience・有効期限の可否が含まれていません。代理リクエストが成功したという 結果を、トークンの有効性の証拠として再利用しないことが、この単元の出発点です。

audienceの実験の読み方

このVMのAPIは、labhub-kcsa-apiを受信者として使います。labhub-kcsa-reportを指定して 発行したトークンは、このAPIのConfigMapの読み取りで401になります。同じトークンをレポートの受信者として 明示してTokenReviewすると、認証結果はtrueになります。トークンが丸ごと壊れていたのではなく、 どの受信者に提示したかが違っていたのです。これは、この単元の実際のk3sのプローブで確認した結果です。

外部のレポートサービスが存在すると仮定した例であり、今回のラボでレポートサーバーをデプロイしたわけでは ありません。実際のサービスなら、許可するaudienceをサーバーの設定で決め、その範囲で検査する必要があります。 リクエスト元が送ってきたaudienceを無条件に受け入れる検査は、受信者を区別する目的を失います。

現場での姿

まずリクエストのアドレスと認証情報の種類を確認し、次に受信者・有効期限・認証結果を見ます。 認証されたあとに、対象のリソース・動詞・ネームスペースとRBACを確認します。すべての403が同じ 原因だと断定せず、レスポンスの理由とリクエストの主体をあわせて残します。匿名のリクエストが常に 401になるわけでもないので、今回の誤ったbearerの観測を、すべてのリクエストに一般化しません。

PodとSAのautomountServiceAccountTokenをfalseにするのは、自動のトークンマウントを 避ける設定です。管理者のTokenRequestの発行権限がなくなる設定ではありません。 今回のPodは、自動マウントを無効にしてトークンを明示的に発行しておき、2つの効果を混ぜないようにします。 一般的なprojected tokenはkubeletがローテーションしますが、今回ファイルとして保存したトークンを kubeletが代わりに更新してくれることはありません。2つの受け渡し方式を区別して運用する必要があります。

次のレッスンへのつながり

次の記事では、アカウントの再作成でUIDが変わる状況を見ます。そのあとのラボで、 自分のリソースは200・ほかのチームのリソースは403を基準線として作成し、別のaudienceのトークンを提示したときの 401とTokenReviewの結果を比較します。トークンの原文を、ターミナル・レポート・掲示板に貼り付けません。 クレームとハッシュだけを記録し、デコード・認証・認可のどの観測なのかを、横に書き添えてください。

公式ドキュメント