クラスタ全体のRBAC監査
目標
クラスター全体のRBACを、実際に監査します。ワイルドカード権限と危険な動詞を持つClusterRoleを見つけ出し、
ServiceAccountの実効権限をkubectl auth can-iで測定し、最小権限のRoleを新しく作成して
その境界が実際に機能していることを証明したうえで、根拠が入った監査レポートを作成します。
なぜ重要なのか
RBACの監査が難しいのは、マニフェストを読むだけでは答えが出ないからです。
1つの主体に複数のバインディングが付き、グループを通じて継承され、組み込みのClusterRoleがaggregationで
統合されることもあります。頭の中で計算せず、apiserverに尋ねてください。
kubectl auth can-i --list --as=が、そのための道具です。
ワイルドカードを別に数えるのには、理由があります。resources: ["*"]は、いまあるリソースだけでなく、
将来CRDとして追加されるリソースまで許可します。「いまは安全だ」という反論が通用しない理由です。
escalate・bind・impersonateは、特に危険なメタ権限です。これらの動詞は「権限を与える権限」
なので、1つあるだけで自分自身を管理者にできます。RBAC監査で最初に探すべき対象です。
最後にステップ6です。最小権限とは、「必要なものを与えた」ことではなく、「必要ではないものができない」ことです。 読み取りができるかを確認して終わりにするのは、半分でしかありません。削除ができないか、ほかのネームスペースではできないかまで 確認して初めて、境界を証明したことになります。
ステップ
- ディレクトリ
/root/kcsa-auditとネームスペースkcsa-auditを作成し、そのネームスペースにServiceAccountを2つ、auditorとprobeを作成します。どちらも、このステップでは何の権限も付けません。 - クラスターのすべてのClusterRoleのうち、1つのルールの中で
verbsとresourcesの両方が*であるものを探し、名前だけを1行に1つずつ/root/kcsa-audit/wildcard-clusterroles.txtに保存します。 kubectl auth can-i --listを--as=system:serviceaccount:kcsa-audit:probeと-n kcsa-auditで実行し、その出力全体を加工せずそのまま/root/kcsa-audit/probe-can-i.txtに保存します。probeは、このラボが終わるまでどのロールもバインドしない比較の基準なので、あとからでも権限を付けてはいけません。- クラスターのすべてのClusterRoleのうち、
verbsにescalate、bind、impersonateのどれか1つでも文字どおり含むものを探し、名前だけを1行に1つずつ/root/kcsa-audit/dangerous-verbs.txtに保存します。 system:serviceaccount:kcsa-audit:defaultとして3つのことを尋ね、結果を/root/kcsa-audit/default-sa.txtに키=값の3行(プレースホルダーはキーと値です)で保存します。create-pods=(ネームスペースkcsa-auditでのPodのcreate)、get-secrets=(ネームスペースkcsa-auditでのsecretsのget)、list-nodes=(クラスタースコープのnodesのlist)です。値はyes/noをそのまま書きます。- ネームスペース
kcsa-auditにRoleconfigmap-readerを作成します。ルールはちょうど1つで、apiGroupsはコアグループ1つ、resourcesはconfigmaps1つ、verbsはget、list、watchの3つだけです。そしてRoleBindingauditor-configmap-readerでSAauditorにバインドします。作成したあと、auth can-iで(a)kcsa-auditでconfigmapsのlistができるか、(b)同じ場所でdeleteはできないか、(c)defaultネームスペースではlistもできないかを確認します。 /root/kcsa-audit/rbac-audit-report.mdを作成します。次の4行がセクション見出しとして正確に入っている必要があります。## 와일드카드 권한、## 위험 동사、## 기본 서비스어카운트、## 최소 권한 적용です(順に、韓国語で「ワイルドカード権限」「危険な動詞」「デフォルトのServiceAccount」「最小権限の適用」を意味する見出しです)。本文に、次の5つの単語が記載されている必要があります。cluster-admin、escalate、impersonate、configmap-reader、auditorです。そしてステップ2で数えたワイルドカードのClusterRoleの個数を、wildcard-count=<숫자>の形式の行として1行入れます(プレースホルダーは数値です)。
参考
kubectl get clusterroles -o json | jq -r '.items[] | ... | .metadata.name'の形で取り出すと便利です。selectとanyを組み合わせて、ルールの配列を走査してください。- ルールに
verbsやresourcesがそもそもない場合(非リソースURLのルールなど)があるため、// []のようなデフォルト値の処理を入れておくと安全です。 - コアAPIグループは、名前が空文字列(
"")です。 - よくあるミス1: ステップ2で、
verbsだけが*のものまで入れることです。2つの条件を同じルールの中で同時に満たす必要があります。 - よくあるミス2: ステップ3で、出力をgrepや並べ替えで加工して保存することです。採点は同じコマンドをもう一度実行して照合するため、そのまま保存する必要があります。
- よくあるミス3: ステップ6で、ロールバインディングの対象を
probeにすることです。probeは基準線なので、権限が付くとステップ3がやり直しになります。ロールはauditorに付けます。
監査の作業スペースを準備する
ディレクトリ/root/kcsa-auditとネームスペースkcsa-auditを作成し、そのネームスペースにServiceAccountを2つ、auditorとprobeを作成してください。どちらも、このステップでは何の権限も付けません。
成果物のディレクトリ、ネームスペース、そしてServiceAccountを2つ作成します。1つはあとで最小権限のロールを受け取る対象で、もう1つは最後まで何の権限も受け取らない比較の基準です。基準がなければ、「権限が増えた」とは言えません。
ワイルドカード権限のClusterRoleを見つける
クラスターのすべてのClusterRoleのうち、1つのルールの中でverbsとresourcesの両方が*であるものを探し、名前だけを1行に1つずつ/root/kcsa-audit/wildcard-clusterroles.txtに保存してください。
1つのルールの中で、verbsとresourcesの両方が*であるものを探します。ルールは配列で、1つのClusterRoleに複数ある場合があるため、どれか1つでも条件を満たせば、そのロールを一覧に入れます。jqのselectとanyを組み合わせれば、1行でできます。
権限のないServiceAccountの基準線を取る
kubectl auth can-i --listを--as=system:serviceaccount:kcsa-audit:probeと-n kcsa-auditで実行し、その出力全体を加工せずそのまま/root/kcsa-audit/probe-can-i.txtに保存してください。probeは、このラボが終わるまでどのロールもバインドしない比較の基準なので、あとからでも権限を付けてはいけません。
auth can-iには、個別の質問ではなく全体の一覧を取り出すオプションがあります。対象は--asで指定し、ネームスペースの範囲の権限も見るには、-nを一緒に指定する必要があります。出力をgrepや並べ替えで加工せず、そのまま保存してください。ここに出る数行が「何の権限もないアカウント」の基準線であり、このアカウントには最後まで、どのロールも付けてはいけません。
危険な動詞を持つClusterRoleを検知する
クラスターのすべてのClusterRoleのうち、verbsにescalate、bind、impersonateのどれか1つでも文字どおり含むものを探し、名前だけを1行に1つずつ/root/kcsa-audit/dangerous-verbs.txtに保存してください。
3つの動詞がそれぞれ何を可能にするのかを思い浮かべてみると、なぜまとめて見るのかがわかります。ここでは、動詞が文字どおり書かれているものだけを数えます。ワイルドカードは、前のステップですでに別に集計しています。
デフォルトのServiceAccountに何ができるか
system:serviceaccount:kcsa-audit:defaultとして3つのことを尋ね、結果を/root/kcsa-audit/default-sa.txtに키=값の3行(プレースホルダーはキーと値です)で保存してください。create-pods=(ネームスペースkcsa-auditでのPodのcreate)、get-secrets=(ネームスペースkcsa-auditでのsecretsのget)、list-nodes=(クラスタースコープのnodesのlist)です。値はyes/noをそのまま書きます。
すべてのネームスペースにはdefaultというServiceAccountが自動で存在し、PodがSAを指定しない場合はこれを使います。このアカウントに何ができるかを自分で尋ねて、答えをそのまま書き写してください。クラスタースコープのリソースを尋ねるときは、ネームスペースのオプションは不要です。
最小権限のRoleを作成して境界を証明する
ネームスペースkcsa-auditにRoleconfigmap-readerを作成してください。ルールはちょうど1つで、apiGroupsはコアグループ1つ、resourcesはconfigmaps1つ、verbsはget、list、watchの3つだけです。そしてRoleBindingauditor-configmap-readerでSAauditorにバインドします。作成したあと、auth can-iで(a)kcsa-auditでconfigmapsのlistができるか、(b)同じ場所でdeleteはできないか、(c)defaultネームスペースではlistもできないかを確認します。
1つのルールに、必要なものだけを入れます。コアAPIグループは、名前が空文字列です。作成したあとは、望むことができるかだけでなく、望まないことができないかも確認して初めて、最小権限だと言えます。特に、ほかのネームスペースでできないかを確認してください。
監査レポートにまとめる
/root/kcsa-audit/rbac-audit-report.mdを作成してください。次の4行がセクション見出しとして正確に入っている必要があります。## 와일드카드 권한、## 위험 동사、## 기본 서비스어카운트、## 최소 권한 적용です(順に、韓国語で「ワイルドカード権限」「危険な動詞」「デフォルトのServiceAccount」「最小権限の適用」を意味する見出しです)。本文に、次の5つの単語が記載されている必要があります。cluster-admin、escalate、impersonate、configmap-reader、auditorです。そしてステップ2で数えたワイルドカードのClusterRoleの個数を、wildcard-count=<숫자>の形式の行として1行入れます(プレースホルダーは数値です)。
前のステップの成果物を根拠にして、1つの文書を作成します。セクション見出しは指示された形そのままである必要があり、ステップ2で数えた個数を数字で書く行が1つ必要です。その数字は、採点の時点でもう一度計算して照合します。