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

CNPE — クラウドネイティブプラットフォームエンジニア

プラットフォームAPIを設計し囲いを立てる

TT Labで続きを見る

目標

AppClaimというセルフサービスAPIをCRDで設計して適用し、スキーマとCELで誤ったリクエストを拒否するようにし、RBACでテナントにできることとできないことを分けたうえで、払い出す個数に上限をかけます。

なぜ重要なのか

プラットフォームAPIとセルフサービスは、CNPEで扱う中核のドメインです。そして、このドメインで問われるのは、CRDを作れるかどうかではなく、何をAPIサーバーに拒否させるかを決められるかです。

この判断が重要なのは、拒否する場所が2か所しかないからです。APIサーバーが拒否すれば、ユーザーはすぐに理由を見られます。コントローラーがあとで失敗すると、ユーザーは受け付けられたと信じて待ちます。前の段階でかけられるものを後ろに回すと、その分だけ人が迷います。

このラボには、AppClaimを実際のアプリに変えるコントローラーがありません。しかし、kube-apiserverは本物なので、CRDの登録、OpenAPIの検証、CELの評価、RBACの判定、ResourceQuotaのアドミッションが、すべて実際に動作します。そのため、ここで確認する拒否と許可は、実際のクラスターで起きることと同じです。

作業ディレクトリは/root/cnpe-apiで、テナントのネームスペースはtenant-blueです。

ステップ

  1. /root/cnpe-api/appclaim-crd.yamlにCRDを書きます。グループはplatform.labhub.io、種類はAppClaim、複数形はappclaims、スコープはNamespacedです。バージョンはv1alpha1とv1の2つで、どちらもservedであり、保存バージョンはv1です。v1alpha1とv1のどちらにも、statusサブリソースと、.spec.tierを表示する出力カラムを置きます。2つのバージョンのルートでspecを必須にし、spec内でtier・replicas・maxReplicasを必須にします。tierは文字列、2つの数量は1以上の整数です。書き終えたらapplyします。
  2. v1alpha1とv1のそれぞれのspecに、検証を加えます。tierはbronze、silver、goldだけを許可し、CELルールでreplicasがmaxReplicasを超えないようにします。拒否メッセージには、maxReplicasというフィールド名が含まれている必要があります。2つのバージョンで、bronze(1/1)・silver(2/6)・gold(3/3)の正常なリクエストは許可され、spec全体の欠落・null・空のオブジェクト、必須フィールドの欠落、誤ったデータ型、0・負の数は拒否されることを、サーバーdry-runで確認します。括弧内はreplicas/maxReplicasです。
  3. ネームスペースtenant-blueを作成し、/root/cnpe-api/claim-checkout.yamlにAppClaimcheckoutを書きます。tierはsilver、replicasは2、maxReplicasは6です。applyしたあと、2つのバージョンで参照したUIDとspecが同じであることを確認します。
  4. v1alpha1とv1のそれぞれのspecに遷移ルールを加えて、tierを不変にします。ルールはoldSelfを参照する必要があり、拒否メッセージにはtierが含まれている必要があります。tierをそのままにしてreplicasだけを変更する操作は、引き続き通過する必要があります。
  5. /root/cnpe-api/tenant-rbac.yamlにServiceAccountblue-dev、Roleappclaim-author、RoleBindingappclaim-authorを書きます。RoleはAppClaimに対してget、list、watch、create、update、patchを許可します。バインディングは、そのServiceAccountを指している必要があります。
  6. Roleにdeleteがなく、resourcequotasとrolesとrolebindingsを作成できず、secretsを読めないことを、kubectl auth can-iで確認します。AppClaim statusのpatch・updateと、kube-systemのAppClaim listも、拒否される必要があります。正常なgetがyesであることを対照し、通信・認証のエラーをnoと解釈しないでください。Roleのverbs、resources、apiGroupsのどこにも、*がない必要があります。
  7. AppClaimsearchをもう1つ作成し、/root/cnpe-api/claim-quota.yamlにResourceQuotablue-claimsを書きます。count/appclaims.platform.labhub.ioの上限は2です。クォータのstatus.usedが2で埋まることを確認し、空なら、CRDのEstablished・API discovery・クォータコントローラーを診断して再確認したうえで、3つ目のAppClaimが実際に止められることを確認します。
  8. /root/cnpe-api/api-report.txtに、storage_version、claims、quota_hard、tenant_can_deleteの4行を키=값の形式(プレースホルダーはキーと値です)で書きます。4つの値はすべて、クラスターから直接参照したものである必要があります。

参考

CRDの骨格と2つのバージョンを決める

/root/cnpe-api/appclaim-crd.yamlにCRDを書きます。グループはplatform.labhub.io、種類はAppClaim、複数形はappclaims、スコープはNamespacedです。バージョンはv1alpha1とv1の2つで、どちらもservedであり、保存バージョンはv1です。v1alpha1とv1のどちらにも、statusサブリソースと、.spec.tierを表示する出力カラムを置きます。2つのバージョンのルートでspecを必須にし、spec内でtier・replicas・maxReplicasを必須にします。tierは文字列、2つの数量は1以上の整数です。書き終えたらapplyします。

保存バージョンは1つのバージョンだけがtrueです。古いバージョンもservedにしておかなければ、そのバージョンのリクエストを受け付けません。spec内のrequiredはspecそのものを必須にしないため、ルートのrequiredも必要です。statusサブリソースは、状態の書き込みを別の経路に分離します。

値の集合とフィールド間の関係を縛る

v1alpha1とv1のそれぞれのspecに、検証を加えます。tierはbronze、silver、goldだけを許可し、CELルールでreplicasがmaxReplicasを超えないようにします。拒否メッセージには、maxReplicasというフィールド名が含まれている必要があります。2つのバージョンで、bronze(1/1)・silver(2/6)・gold(3/3)の正常なリクエストは許可され、spec全体の欠落・null・空のオブジェクト、必須フィールドの欠落、誤ったデータ型、0・負の数は拒否されることを、サーバーdry-runで確認します。括弧内はreplicas/maxReplicasです。

値1つの形はenumが、2つのフィールドの関係はCELが押さえます。ルールはspecプロパティの下に、x-kubernetes-validationsで付けます。拒否メッセージは、ユーザーが実際に読む唯一の文なので、フィールド名を入れてください。

最初のセルフサービスリクエストを受け付ける

ネームスペースtenant-blueを作成し、/root/cnpe-api/claim-checkout.yamlにAppClaimcheckoutを書きます。tierはsilver、replicasは2、maxReplicasは6です。applyしたあと、2つのバージョンで参照したUIDとspecが同じであることを確認します。

2つのバージョンが別のオブジェクトを作るわけではありません。UIDとspecを比較してください。statusサブリソースを有効にすると、通常の作成・変更リクエストのstatusは無視されます。このラボにはAppClaimコントローラーがないため、受付の成功を、実際のアプリのデプロイ完了と解釈しないでください。

一度決めたら変更できないフィールドを作る

v1alpha1とv1のそれぞれのspecに遷移ルールを加えて、tierを不変にします。ルールはoldSelfを参照する必要があり、拒否メッセージにはtierが含まれている必要があります。tierをそのままにしてreplicasだけを変更する操作は、引き続き通過する必要があります。

ルールがoldSelfを参照すると、そのルールは変更のときだけ評価されます。ただし、spec全体をoldSelfと比較すると、レプリカも変更できなくなり、凍結になります。縛るフィールドを名前で書いてください。

テナントが自分でできることを決める

/root/cnpe-api/tenant-rbac.yamlにServiceAccountblue-dev、Roleappclaim-author、RoleBindingappclaim-authorを書きます。RoleはAppClaimに対してget、list、watch、create、update、patchを許可します。バインディングは、そのServiceAccountを指している必要があります。

Roleは権限の定義にすぎず、バインディングを付けて初めて権限が生まれます。作ったあとは、必ずkubectl auth can-iで判定を確認してください。Roleを読むだけでは、最終的な結果はわかりません。

閉じた側を判定で確認する

Roleにdeleteがなく、resourcequotasとrolesとrolebindingsを作成できず、secretsを読めないことを、kubectl auth can-iで確認します。AppClaim statusのpatch・updateと、kube-systemのAppClaim listも、拒否される必要があります。正常なgetがyesであることを対照し、通信・認証のエラーをnoと解釈しないでください。Roleのverbs、resources、apiGroupsのどこにも、*がない必要があります。

開けたものは前のステップで見たので、ここでは閉じた側だけを見ます。削除・クォータ・Role・Secret・statusの変更・別のネームスペースの参照は、すべて明示的なnoである必要があり、Roleのどこにもアスタリスクがあってはいけません。アスタリスクが1つあれば、上の判定がすべてひっくり返ります。

払い出しに上限をかけて、止まるかを見る

AppClaimsearchをもう1つ作成し、/root/cnpe-api/claim-quota.yamlにResourceQuotablue-claimsを書きます。count/appclaims.platform.labhub.ioの上限は2です。クォータのstatus.usedが2で埋まることを確認し、空なら、CRDのEstablished・API discovery・クォータコントローラーを診断して再確認したうえで、3つ目のAppClaimが実際に止められることを確認します。

RBACは「できるか」に答えますが、「いくつまで」には答えません。個数はクォータが数えます。status.usedが空だという事実だけで、原因を断定しないでください。登録直後は反映を待ち、空のままなら、Established・API discovery・コントローラーの状態を確認します。やみくもにクォータを削除すると、制限を取り除くことになります。

プラットフォームAPIの現在の状態を値として残す

/root/cnpe-api/api-report.txtに、storage_version、claims、quota_hard、tenant_can_deleteの4行を키=값の形式(プレースホルダーはキーと値です)で書きます。4つの値はすべて、クラスターから直接参照したものである必要があります。

4つの値とも、参照して書いてください。保存バージョンはCRDから、AppClaimの数と上限はネームスペースから、削除できるかどうかは権限の判定から得られます。採点ツールが同じ値を再計算して突き合わせます。