このドキュメントでは、ロールベース アクセス制御(RBAC)ポリシーの計画に関するベスト プラクティスを説明します。Google Kubernetes Engine(GKE)に RBAC を実装する方法については、ロールベース アクセス制御を構成するをご覧ください。
RBAC は Kubernetes のコア セキュリティ機能です。きめ細かい権限を作成して、ユーザーとワークロードがクラスタ内のリソースに対して実行できるアクションを管理できます。プラットフォーム管理者として RBAC のロールを作成し、作成したロールをサブジェクト(サービス アカウントや Google グループなどの認証済みユーザー)にバインドします。
始める前に
このドキュメントを読む前に、次のコンセプトをよく理解しておいてください。
このガイダンスのチェックリストについては、チェックリストの概要をご覧ください。
RBAC の仕組み
RBAC では、次のタイプのロールとバインディングがサポートされています。
- ClusterRole: 任意の Namespace またはクラスタ全体に適用できる一連の権限。
- Role: 1 つの Namespace に制限されている一連の権限。
- ClusterRoleBinding: クラスタ内のすべての Namespace のユーザーまたはグループに
ClusterRole
をバインドします。 - RoleBinding:
Role
またはClusterRole
を特定の Namespace 内のユーザーまたはグループにバインドします。
Role
または ClusterRole
で権限を rules
として定義します。ロールの各 rules
フィールドは、API グループ、その API グループ内の API リソース、それらのリソースで使用できる動詞(アクション)で構成されています。必要に応じて、resourceNames
フィールドを使用して、動詞のスコープを API リソースの名前付きインスタンスに設定できます。例については、特定のリソース インスタンスへのアクセスを制限するをご覧ください。
ロールを定義したら、RoleBinding
または ClusterRoleBinding
を使用してロールをサブジェクトにバインドします。1 つの Namespace と複数の Namespace のどちらで権限を付与するかに基づいて、バインディングのタイプを選択します。
RBAC ロールの設計
最小権限の原則を使用する
RBAC ロールで権限を割り当てる場合は、最小権限の原則に従い、タスクの実行に必要な最小限の権限を付与します。最小権限の原則を使用すると、クラスタが侵害された場合の権限昇格のリスクが軽減され、過剰なアクセスによってセキュリティ インシデントが発生する可能性が低くなります。
ロールを設計するときには、escalate
動詞または bind
動詞、PersistentVolume の create
アクセス、証明書署名リクエストの create
アクセスなど、一般的な権限昇格のリスクを慎重に考慮してください。リスクの一覧については、Kubernetes RBAC - 権限昇格のリスクをご覧ください。
デフォルトのロールとグループを使用しない
Kubernetes では、API の検出やマネージド コンポーネント機能の有効化に使用できるデフォルトの ClusterRole と ClusterRoleBinding が作成されます。これらのデフォルトのロールによって付与される権限は、ロールによっては広範囲にわたる場合があります。Kubernetes には、(system:
接頭辞で識別される)デフォルトのユーザーとユーザー グループもあります。デフォルトでは、Kubernetes と GKE は、これらのロールをデフォルトのグループとさまざまなサブジェクトに自動的にバインドします。Kubernetes によって作成されるすべてのデフォルトのロールとバインディングの一覧については、デフォルトのロールとロール バインディングをご覧ください。
次の表に、デフォルトのロール、ユーザー、グループを示します。これらのロール、ユーザー、グループを利用する場合は、慎重に評価することをおすすめします。これは、これらのリソースを利用すると、クラスタのセキュリティ ポスチャーに意図しない結果をもたらす可能性があるためです。
名前 | 型 | 説明 |
---|---|---|
cluster-admin |
ClusterRole | クラスタ内の任意のリソースに対してあらゆる操作を行う権限をサブジェクトに付与します。 |
system:anonymous |
ユーザー | Kubernetes は、認証情報が指定されていない API サーバー リクエストにこのユーザーを割り当てます。 このユーザーにロールをバインドすると、認証されていないユーザーに、そのロールによって付与される権限が付与されます。 |
system:unauthenticated |
グループ | Kubernetes は、認証情報が指定されていない API サーバー リクエストにこのグループを割り当てます。 このグループにロールをバインドすると、認証されていないユーザーに、そのロールによって付与される権限が付与されます。 |
system:authenticated |
グループ | GKE は、Google アカウント(すべての Gmail アカウントを含む)でログインしているすべてのユーザーが実行する API サーバー リクエストにこのグループを割り当てます。Google アカウントは誰でも作成できるため、 このグループにロールをバインドすると、Google アカウント(すべての Gmail アカウントを含む)を持つすべてのユーザーに、そのロールによって付与される権限が付与されます。 |
system:masters |
グループ | Kubernetes はデフォルトでこのグループに このグループに独自のサブジェクトを追加すると、それらのサブジェクトに対し、クラスタ内のすべてのリソースに対して任意の操作を行えるアクセス権が付与されます。 |
可能であれば、デフォルトのユーザー、ロール、グループを含むバインディングを作成しないでください。これにより、クラスタのセキュリティ対策で意図しない結果が生じる可能性があります。次に例を示します。
- デフォルトの
cluster-admin
ClusterRole をsystem:unauthenticated
グループにバインドすると、未認証のユーザーがクラスタ内のすべてのリソース(Secret を含む)にアクセスできるようになります。このような高い権限を持つバインディングは、大規模なマルウェア キャンペーンなどの攻撃の標的にされやすくなります。 - カスタムロールを
system:unauthenticated
グループにバインドすると、そのロールによって付与される権限が未認証のユーザーに付与されることになります。
可能な場合は、次のガイドラインを使用してください。
system:masters
グループに独自のサブジェクトを追加しないでください。system:unauthenticated
グループを RBAC ロールにバインドしないでください。system:authenticated
グループを RBAC ロールにバインドしないでください。system:anonymous
ユーザーを RBAC ロールにバインドしないでください。cluster-admin
ClusterRole は、独自のサブジェクトまたはデフォルトのユーザーとグループのいずれにもバインドしないでください。アプリケーションで多数の権限が必要な場合は、厳密に必要な権限を特定し、その目的のための特定のロールを作成します。- サブジェクトをバインドする前に、他のデフォルトのロールによって付与される権限を評価します。
- グループのメンバーを変更する前に、デフォルト グループにバインドされているロールを評価します。
デフォルトのロールとグループの使用を検出して防止する
クラスタを評価して、system:anonymous
ユーザー、system:unauthenticated
グループ、system:authenticated
グループが、ClusterRoleBinding と RoleBinding の両方を使用してバインドされているかどうかを確認する必要があります。
ClusterRoleBinding
サブジェクト
system:anonymous
、system:unauthenticated
、またはsystem:authenticated
を含む ClusterRoleBinding の名前を一覧表示します。kubectl get clusterrolebindings -o json \ | jq -r '["Name"], ["-----"], (.items[] | select((.subjects | length) > 0) | select(any(.subjects[]; .name == "system:anonymous" or .name == "system:unauthenticated" or .name == "system:authenticated")) | [.metadata.namespace, .metadata.name]) | @tsv'
出力には、次の ClusterRoleBinding のみが一覧表示されます。
Name ---- "system:basic-user" "system:discovery" "system:public-info-viewer"
出力にデフォルト以外の追加のバインディングが含まれている場合は、バインディングごとに次の操作を行います。出力にデフォルト以外のバインディングが含まれていない場合は、次の手順をスキップします。
バインディングに関連付けられているロールの権限を一覧表示します。
kubectl get clusterrolebinding CLUSTER_ROLE_BINDING_NAME -o json \ | jq ' .roleRef.name +" " + .roleRef.kind' \ | sed -e 's/"//g' \ | xargs -l bash -c 'kubectl get $1 $0 -o yaml'
CLUSTER_ROLE_BINDING_NAME
は、デフォルト以外の ClusterRoleBinding の名前に置き換えます。出力は次のようになります。
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: ... rules: - apiGroups: - "" resources: - secrets verbs: - get - watch - list
出力内の権限がデフォルトのユーザーまたはグループに付与されても安全であると判断した場合は、何もする必要はありません。バインディングによって付与される権限が安全ではないと判断した場合は、次のステップに進みます。
安全でないバインディングをクラスタから削除します。
kubectl delete clusterrolebinding CLUSTER_ROLE_BINDING_NAME
CLUSTER_ROLE_BINDING_NAME
は、削除する ClusterRoleBinding の名前に置き換えます。
RoleBinding
サブジェクト
system:anonymous
、system:unauthenticated
、またはsystem:authenticated
を持つ RoleBinding の Namespace と名前を一覧表示します。kubectl get rolebindings -A -o json \ | jq -r '["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(any(.subjects[]; .name == "system:anonymous" or .name == "system:unauthenticated" or .name == "system:authenticated")) | [.metadata.namespace, .metadata.name]) | @tsv'
クラスタが正しく構成されている場合、出力は空白になります。出力にデフォルト以外のバインディングが含まれている場合は、バインディングごとに次の操作を行います。出力が空白の場合は、次の手順をスキップします。
RoleBinding の名前のみがわかっている場合は、次のコマンドを使用して、すべての Namespace で一致する RoleBinding を検索できます。
kubectl get rolebindings -A -o json \ | jq -r '["Namespace", "Name"], ["---------", "-----"], (.items[] | select((.subjects | length) > 0) | select(.metadata.name == "ROLE_BINDING_NAME") | [.metadata.namespace, .metadata.name]) | @tsv'
ROLE_BINDING_NAME
は、デフォルト以外の RoleBinding の名前に置き換えます。バインディングに関連付けられている Role の権限を一覧表示します。
kubectl get rolebinding ROLE_BINDING_NAME --namespace ROLE_BINDING_NAMESPACE -o json \ | jq ' .roleRef.name +" " + .roleRef.kind' \ | sed -e 's/"//g' \ | xargs -l bash -c 'kubectl get $1 $0 -o yaml --namespace ROLE_BINDING_NAMESPACE'
次のように置き換えます。
ROLE_BINDING_NAME
: デフォルト以外の RoleBinding の名前。ROLE_BINDING_NAMESPACE
: デフォルト以外の RoleBinding の Namespace。
出力は次のようになります。
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: ... rules: - apiGroups: - "" resources: - secrets verbs: - get - watch - list
出力内の権限がデフォルトのユーザーまたはグループに付与されても安全であると判断した場合は、何もする必要はありません。バインディングによって付与される権限が安全ではないと判断した場合は、次のステップに進みます。
安全でないバインディングをクラスタから削除します。
kubectl delete rolebinding ROLE_BINDING_NAME --namespace ROLE_BINDING_NAMESPACE
次のように置き換えます。
ROLE_BINDING_NAME
: 削除する RoleBinding の名前。ROLE_BINDING_NAMESPACE
: 削除する RoleBinding の Namespace。
Namespace レベルで権限のスコープを設定する
ワークロードまたはユーザーのニーズに応じて、バインディングとロールを次のように使用します。
- 1 つの Namespace 内のリソースへのアクセス権を付与するには、
Role
とRoleBinding
を使用します。 - 複数の Namespace 内のリソースへのアクセス権を付与するには、
ClusterRole
と各 Namespace のRoleBinding
を使用します。 - すべての Namespace 内のリソースへのアクセス権を付与するには、
ClusterRole
とClusterRoleBinding
を使用します。
権限を付与する Namespace はできるだけ少なくしてください。
ワイルドカードを使用しない
*
文字は、すべてに適用されるワイルドカードです。ルールにワイルドカードを使用しないでください。RBAC ルールでは API グループ、リソース、動詞を明示的に指定してください。たとえば、verbs
フィールドに *
を指定すると、リソースに対する get
、list
、watch
、patch
、update
、deletecollection
、delete
の各権限が付与されます。次の表に、ルールでワイルドカードを避ける例を示します。
推奨 | 非推奨 |
---|---|
- rules: apiGroups: ["apps","extensions"] resources: ["deployments"] verbs: ["get","list","watch"] 動詞 |
- rules: apiGroups: ["*"] resources: ["deployments"] verbs: ["get","list","watch"] 任意の API グループの |
- rules: apiGroups: ["apps", "extensions"] resources: ["deployments"] verbs: ["get", "list", "watch"] 動詞 |
- rules: apiGroups: ["apps", "extensions"] resources: ["deployments"] verbs: ["*"]
|
個別のルールを使用して特定のリソースに対する最小権限アクセスを付与する
ルールを計画するときには、次に示す各ロールで最小権限ルールをより効率的に設計するための大まかな手順をお試しください。
- サブジェクトがアクセスする必要がある各リソースに対する動詞ごとに個別の RBAC ルールを作成します。
- ルールのドラフトを作成したら、ルールを分析して、複数のルールに同じ
verbs
リストがあるかどうかを確認します。このようなルールを結合して 1 つのルールにします。 - 残りのルールはすべて互いに区別します。
このアプローチでは、ルールの設計がより整理されたものになります。同じ動詞を複数のリソースに付与するルールが結合され、異なる動詞をリソースに付与するルールは分離されます。
たとえば、ワークロードで deployments
リソースに対する get 権限と、daemonsets
リソースに対する list
と watch
が必要な場合は、ロールを作成するときに、分離したルール使用する必要があります。RBAC ロールをワークロードにバインドすると、deployments
に対する watch
が使用できなくなります。
別の例として、ワークロードで pods
リソースと daemonsets
リソースの両方に対する get
と watch
を必要とする場合、ワークロードは両方のリソースで同じ動詞を必要とするため、これらを 1 つのルールに結合できます。
次の表ではいずれのルール設計も機能しますが、分割されているルールではニーズに基づいてリソース アクセスがより細かく制限されます。
推奨 | 非推奨 |
---|---|
- rules: apiGroups: ["apps"] resources: ["deployments"] verbs: ["get"] - rules: apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["list", "watch"] Deployment に対する |
- rules: apiGroups: ["apps"] resources: ["deployments", "daemonsets"] verbs: ["get","list","watch"] Deployment と DaemonSet の両方に対する動詞を付与します。 |
- rules: apiGroups: ["apps"] resources: ["daemonsets", "deployments"] verbs: ["list", "watch"] サブジェクトが |
- rules: apiGroups: ["apps"] resources: ["daemonsets"] verbs: ["list", "watch"] - rules: apiGroups: ["apps"] resources: ["deployments"] verbs: ["list", "watch"] 分割されているこれらのルールは、結合されたルールと同じ結果になりますが、ロールのマニフェストで不要な煩雑さが生じます。 |
特定のリソース インスタンスへのアクセスを制限する
RBAC では、ルールの resourceNames
フィールドを使用して、リソースの特定の名前付きインスタンスへのアクセスを制限できます。たとえば、seccomp-high
ConfigMap のみに対する update
が必要な RBAC ロールを作成する場合は、resourceNames
を使用してその ConfigMap のみを指定できます。可能な限り resourceNames
を使用してください。
推奨 | 非推奨 |
---|---|
- rules: apiGroups: [""] resources: ["configmaps"] resourceNames: ["seccomp-high"] verbs: ["update"]
|
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["update"] サブジェクトは、 |
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["list"] - rules: apiGroups: [""] resources: ["configmaps"] resourceNames: ["seccomp-high"] verbs: ["update"] Namespace 内のすべての ConfigMap( |
- rules: apiGroups: [""] resources: ["configmaps"] verbs: ["update", "list"] すべての ConfigMap に対する |
サービス アカウントによる RBAC リソースの変更を許可しない
rbac.authorization.k8s.io
API グループで bind
、escalate
、create
、update
、または patch
権限を持つ Role
または ClusterRole
リソースは、どの Namespace 内のサービス アカウントにもバインドしないでください。特に escalate
と bind
では、攻撃者が RBAC に組み込まれているエスカレーション防止メカニズムを回避できる可能性があります。
Kubernetes サービス アカウント
ワークロードごとに Kubernetes サービス アカウントを作成する
ワークロードごとに個別の Kubernetes サービス アカウントを作成します。そのサービス アカウントに、最小権限の Role
または ClusterRole
をバインドします。
デフォルトのサービス アカウントを使用しない
Kubernetes は、すべての Namespace に default
という名前のサービス アカウントを作成します。default
サービス アカウントは、マニフェストでサービス アカウントを明示的に指定していない Pod に自動的に割り当てられます。Role
または ClusterRole
を default
サービス アカウントにバインドしないようにします。Kubernetes は、これらのロールで付与されたアクセス権を必要としない Pod に default
サービス アカウントを割り当てることがあります。
サービス アカウント トークンを自動的にマウントしない
Pod 仕様の automountServiceAccountToken
フィールドは、Kubernetes サービス アカウントの認証情報トークンを Pod に挿入するように Kubernetes に指示します。Pod はこのトークンを使用して、Kubernetes API サーバーに認証済みリクエストを送信できます。このフィールドのデフォルト値は true
です。
すべての GKE バージョンで、Pod が API サーバーと通信する必要がない場合は Pod 仕様で automountServiceAccountToken=false
を設定します。
Secret ベースのトークンよりもエフェメラル トークンを優先する
デフォルトでは、ノードの kubelet プロセスは、Pod ごとに自動的にローテーションされる有効期間の短いサービス アカウント トークンを取得します。Pod 仕様で automountServiceAccountToken
フィールドを false
に設定しない限り、kubelet はこのトークンを予測ボリュームとして Pod にマウントします。Pod から Kubernetes API への呼び出しを行うと、このトークンを使用して API サーバーに対する認証が行われます。
サービス アカウント トークンを手動で取得する場合は、Kubernetes Secret を使用してトークンを保存しないでください。Secret ベースのサービス アカウント トークンは以前の認証情報であり、有効期限がなく、自動的にローテーションされません。サービス アカウントの認証情報が必要な場合は、TokenRequest
API を使用して、自動的にローテーションされる有効期間の短いトークンを取得します。
RBAC 権限を継続的に確認する
RBAC のロールとアクセス権を定期的に確認し、潜在的なエスカレーション パスと冗長なルールを特定します。たとえば、特別な権限を含む Role
を削除済みのユーザーにバインドする RoleBinding
を削除しない状況を考えてみます。攻撃者が、削除済みユーザーと同じ名前のユーザー アカウントを Namespace に作成すると、その Role
にバインドされ、同じアクセス権を継承します。定期的な確認を行うことでこのリスクを最小限に抑えることができます。
チェックリストの概要
次のステップ
- GKE の強化に関するアドバイスを読む。
- Kubernetes RBAC のベスト プラクティスを読む。
- その他のベスト プラクティスを確認する。
- 一般的なクラスタロールのサンプル マニフェストを確認する。