このページでは、ロールベースのアクセス制御(RBAC)ポリシーの計画に関するベスト プラクティスを説明します。Google Kubernetes Engine(GKE)に RBAC を実装する方法については、ロールベースのアクセス制御を構成するをご覧ください。
RBAC は Kubernetes のコア セキュリティ機能です。きめ細かい権限を作成して、ユーザーとワークロードがクラスタ内のリソースに対して実行できるアクションを管理できます。プラットフォーム管理者として RBAC のロールを作成し、それらのロールをサービス アカウントやグループなどの認証済みユーザーであるサブジェクトにバインドにします。
始める前に
次のコンセプトを理解しておいてください。
このガイダンスのチェックリストについては、チェックリストの概要をご覧ください。
RBAC の仕組み
RBAC では、次のタイプのロールとバインディングがサポートされています。
- ClusterRole: 任意の名前空間またはクラスタ全体に適用できる一連の権限。
- ロール: 名前空間が 1 つに制限されている一連の権限。
- ClusterRoleBinding: クラスタ内のすべての名前空間のユーザーまたはグループに
ClusterRole
をバインドします。 - RoleBinding: 特定の名前空間内のユーザーまたはグループに
Role
またはClusterRole
をバインドします。
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 を独自のサブジェクトまたはデフォルトのユーザーとグループのいずれにもバインドしないでください。アプリケーションに多数の権限が必要な場合は、必要な権限を正確に特定し、その目的のための特定のロールを作成します。- サブジェクトをバインドする前に、他のデフォルトのロールによって付与される権限を評価します。
- グループのメンバーを変更する前に、デフォルト グループにバインドされているロールを評価します。
デフォルト グループの使用を防止する
gcloud CLI を使用して、system:unauthenticated
グループと system:authenticated
グループ、または system:anonymous
ユーザーを参照するクラスタのデフォルト以外の RBAC バインディングを無効にできます。新しい GKE クラスタを作成する場合や、既存のクラスタを更新する場合は、次のフラグの 1 つまたは両方を使用します。これらのフラグを使用しても、これらのグループを参照するデフォルトの Kubernetes バインディングが無効になることはありません。これらのフラグには、GKE バージョン 1.30.1-gke.1283000 以降が必要です。
--no-enable-insecure-binding-system-authenticated
:system:authenticated
を参照するデフォルト以外のバインディングを無効にします。--no-enable-insecure-binding-system-unauthenticated
:system:unauthenticated
とsystem:anonymous
を参照するデフォルト以外のバインディングを無効にします。
デフォルトのロールとグループの使用を検出して削除する
クラスタが RBAC バインディングでこれらのユーザーとグループを参照しているかどうかを確認するには、クラスタまたはフリートに対して Kubernetes セキュリティ対策スキャンの標準階層を有効にして、GKE が Google Cloud コンソールのセキュリティ対策ダッシュボードに結果を表示できるようにします。手順については、ワークロード構成の監査を有効にするをご覧ください。
以降のセクションでは、デフォルトのユーザーとグループを参照する特定の RoleBinding または ClusterRoleBinding を見つける方法と、それらのリソースを削除する方法について説明します。
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 つの名前空間内のリソースへのアクセス権を付与するには、
RoleBinding
を持つRole
を使用します。 - 複数の名前空間内のリソースへのアクセス権を付与するには、各名前空間に
RoleBinding
を持つClusterRole
を使用します。 - すべての名前空間内のリソースへのアクセス権を付与するには、
ClusterRoleBinding
を持つClusterRole
を使用します。
権限を付与する名前空間はできるだけ少なくしてください。
ワイルドカードを使用しない
*
文字は、すべてに適用されるワイルドカードです。ルールにワイルドカードを使用しないでください。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
リソースに対する権限が必要なものの、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 リソースの変更を許可しない
任意の名前空間内のサービス アカウントを API グループにマッピングするために、rbac.authorization.k8s.io
で bind
、escalate
、create
、update
、または patch
権限を持つ Role
または ClusterRole
リソースをバインドしないでください。特に 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 のベスト プラクティスを読む。
- その他のベスト プラクティスを確認する。
- 一般的なクラスタロールのサンプル マニフェストを確認する。