

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# テナントの分離
<a name="tenant-isolation"></a>

マルチテナンシーについて考えた場合、共有インフラストラクチャで実行されている他のユーザーやアプリケーションからユーザーやアプリケーションを分離することがよくあります。

Kubernetes は*単一テナントオーケストレーター*です。つまり、コントロールプレーンの 単一インスタンスがクラスター内のすべてのテナント間で共有されます。ただし、マルチテナンシーのアセンブリを作成するために使用できるさまざまな Kubernetes オブジェクトがあります。例えば、名前空間とロールベースのアクセスコントロール (RBAC) を実装して、テナントを相互に論理的に分離できます。同様に、クォータと制限範囲を使用して、各テナントが消費できるクラスターリソースの量を制御できます。ただし、クラスターは強力なセキュリティ境界を提供する唯一のコンストラクトです。これは、 を管理する攻撃者が、そのホストにマウントされた*すべての*シークレット、ConfigMapsボリュームを取得できるためです。また、Kubelet を偽装して、ノードの属性を操作したり、クラスター内で横方向に移動したりすることもできます。

以下のセクションでは、Kubernetes などの単一テナントオーケストレーターを使用するリスクを軽減しながら、テナント分離を実装する方法について説明します。

## ソフトマルチテナンシー
<a name="_soft_multi_tenancy"></a>

ソフトマルチテナンシーでは、 名前空間、ロールとロールのバインディング、ネットワークポリシーなどのネイティブ Kubernetes コンストラクトを使用して、テナント間で論理的な分離を作成します。例えば、RBAC はテナントが互いのリソースにアクセスまたは操作できないようにすることができます。クォータと制限範囲は、各テナントが消費できるクラスターリソースの量を制御しますが、ネットワークポリシーは、異なる名前空間にデプロイされたアプリケーションが相互に通信するのを防ぐのに役立ちます。

ただし、これらのコントロールのいずれも、異なるテナントのポッドがノードを共有できないようにします。より強力な分離が必要な場合は、ノードセレクタ、アンチアフィニティルール、テイントや許容値を使用して、異なるテナントのポッドを別々のノードに強制的にスケジュールできます。これは、多くの場合、*唯一のテナントノード*と呼ばれます。テナントが多い環境では、これはかなり複雑でコストがかかる可能性があります。

**重要**  
名前空間で実装されたソフトマルチテナンシーでは、名前空間がグローバルスコープ型であるため、フィルタリングされた名前空間のリストをテナントに提供できません。テナントが特定の名前空間を表示できる場合は、クラスター内のすべての名前空間を表示できます。

**警告**  
soft-multi-tenancyでは、テナントはデフォルトでクラスター内で実行されるすべてのサービスの CoreDNS をクエリする機能を保持します。攻撃者は、クラスター内の任意のポッド` ..svc.cluster.local`から dig SRV を実行することで、これを悪用する可能性があります。クラスター内で実行されるサービスの DNS レコードへのアクセスを制限する必要がある場合は、 CoreDNS のファイアウォールまたはポリシープラグインの使用を検討してください。詳細については、https://github.com/coredns/policy\#kubernetes-metadata-multi-tenancy-policy を参照してください。

 [Kiosk](https://github.com/kiosk-sh/kiosk) は、ソフトマルチテナンシーの実装に役立つオープンソースプロジェクトです。これは、以下の機能を提供する一連の CRDs とコントローラーとして実装されます。
+  共有 Kubernetes クラスター内のテナントを分離する**アカウントとアカウントユーザー** 
+  アカウントユーザーの**セルフサービス名前空間プロビジョニング** 
+  クラスターを共有するときにサービスの品質と公平性を確保するための**アカウント制限** 
+  安全なテナント分離とセルフサービス**名前空間の初期化のための名前空間テンプレート** 

 [Loft](https://loft.sh) は Kiosk と [DevSpace](https://github.com/devspace-cloud/devspace) の保守者からの商用サービスで、次の機能を追加します。
+  異なる**クラスター内のスペースへのアクセスを許可するためのマルチ**クラスターアクセス
+  **スリープモード**は、非アクティブ期間中にスペース内のデプロイをスケールダウンします。
+  GitHub などの OIDC 認証プロバイダーによる**シングルサインオン** 

ソフトマルチテナンシーで対処できる主なユースケースは 3 つあります。

### エンタープライズ設定
<a name="_enterprise_setting"></a>

1 つ目は、「テナント」が従業員、請負業者、または組織によって承認されているという点で半信頼されているエンタープライズ設定です。各テナントは通常、部門やチームなどの管理部門と連携します。

このタイプの設定では、通常、クラスター管理者が名前空間の作成とポリシーの管理を担当します。また、特定の個人が名前空間を監督される委任管理モデルを実装し、デプロイ、サービス、ポッド、ジョブなどのポリシー関連以外のオブジェクトに対して CRUD オペレーションを実行できるようにする場合もあります。

コンテナランタイムによって提供される分離は、この設定内で許容される場合もあれば、ポッドセキュリティのための追加のコントロールで拡張する必要がある場合もあります。また、より厳密な分離が必要な場合は、異なる名前空間内のサービス間の通信を制限する必要がある場合もあります。

### Kubernetes as a Service
<a name="_kubernetes_as_a_service"></a>

対照的に、Kubernetes as a Service (KaaS) を提供する設定では、ソフトマルチテナンシーを使用できます。KaaS では、アプリケーションは一連の PaaS サービスを提供するコントローラーと CRDs のコレクションとともに共有クラスターでホストされます。テナントは Kubernetes API サーバーと直接やり取りし、ポリシー以外のオブジェクトに対して CRUD オペレーションを実行できます。また、テナントが独自の名前空間を作成および管理できるセルフサービスの 要素もあります。このタイプの環境では、テナントは信頼できないコードを実行していると見なされます。

このタイプの環境でテナントを分離するには、多くの場合、厳密なネットワークポリシーと*ポッドサンドボックス*を実装する必要があります。サンドボクシングは、Firecracker やユーザースペースカーネルなどのマイクロ VM 内でポッドのコンテナを実行する場所です。現在、EKS Fargate を使用してサンドボックスポッドを作成できます。

### Software as a Service (SaaS)
<a name="_software_as_a_service_saas"></a>

ソフトマルチテナンシーの最終的なユースケースは、Software-as-a-Service (SaaS) 設定です。この環境では、各テナントはクラスター内で実行されているアプリケーションの特定の*インスタンス*に関連付けられます。多くの場合、各インスタンスには独自のデータがあり、通常は Kubernetes RBAC から独立した個別のアクセスコントロールを使用します。

他のユースケースとは異なり、SaaS 設定のテナントは Kubernetes API と直接インターフェイスしません。代わりに、SaaS アプリケーションは Kubernetes API とやり取りして、各テナントをサポートするために必要なオブジェクトを作成します。

## Kubernetes コンストラクト
<a name="_kubernetes_constructs"></a>

これらの各インスタンスでは、次のコンストラクトを使用してテナントを分離します。

### 名前空間
<a name="_namespaces"></a>

名前空間は、ソフトマルチテナンシーを実装するための基本です。これにより、クラスターを論理パーティションに分割できます。マルチテナンシーの実装に必要なクォータ、ネットワークポリシー、サービスアカウント、およびその他のオブジェクトは、名前空間に限定されます。

### ネットワークポリシー
<a name="_network_policies"></a>

デフォルトでは、Kubernetes クラスター内のすべてのポッドは相互に通信できます。この動作は、ネットワークポリシーを使用して変更できます。

ネットワークポリシーは、ラベルまたは IP アドレス範囲を使用してポッド間の通信を制限します。テナント間の厳密なネットワーク分離が必要なマルチテナント環境では、ポッド間の通信を拒否するデフォルトのルールと、すべてのポッドが名前解決のために DNS サーバーをクエリできるようにする別のルールから始めることをお勧めします。そうすることで、名前空間内での通信を許可する、より寛容なルールの追加を開始できます。これは、必要に応じてさらに絞り込むことができます。

**注記**  
Amazon [VPC CNI は、Kubernetes ネットワークポリシーをサポートし](https://aws.amazon.com/blogs/containers/amazon-vpc-cni-now-supports-kubernetes-network-policies/)、AWS で Kubernetes を実行するときに機密性の高いワークロードを分離して不正アクセスから保護できるポリシーを作成できるようになりました。つまり、Amazon EKS クラスター内でネットワークポリシー API のすべての機能を使用できます。このレベルのきめ細かな制御により、最小特権の原則を実装できます。これにより、承認されたポッドのみが相互に通信できるようになります。

**重要**  
ネットワークポリシーは必須ですが、十分ではありません。ネットワークポリシーの適用には、Calico や Cilium などのポリシーエンジンが必要です。

### ロールベースのアクセスコントロール (RBAC)
<a name="_role_based_access_control_rbac"></a>

ロールとロールバインディングは、Kubernetes でロールベースのアクセスコントロール (RBAC) を適用するために使用される Kubernetes オブジェクトです。**ロール**には、クラスター内のオブジェクトに対して実行できるアクションのリストが含まれます。**ロールバインディング**は、ロールが適用される個人またはグループを指定します。エンタープライズおよび KaaS 設定では、RBAC を使用して、選択したグループまたは個人によるオブジェクトの管理を許可できます。

### クォータ
<a name="_quotas"></a>

クォータは、クラスターでホストされているワークロードの制限を定義するために使用されます。クォータでは、ポッドが消費できる CPU とメモリの最大量を指定するか、クラスターまたは名前空間に割り当てることができるリソースの数を制限できます。**制限範囲**を使用すると、各制限の最小値、最大値、デフォルト値を宣言できます。

共有クラスターでリソースを上書きすると、リソースを最大化できるため、多くの場合有益です。ただし、クラスターへの無制限のアクセスはリソース不足を引き起こし、パフォーマンスの低下やアプリケーションの可用性の低下につながる可能性があります。ポッドのリクエストの設定が低すぎて、実際のリソース使用率がノードの容量を超えた場合、ノードは CPU またはメモリ負荷を経験し始めます。この場合、ポッドが再起動されたり、ノードから削除されたりすることがあります。

これを防ぐには、マルチテナント環境の名前空間にクォータを課して、テナントがクラスターでポッドをスケジュールするときにリクエストと制限を指定するよう強制する計画を立てる必要があります。また、ポッドが消費できるリソースの量を制限することで、潜在的なサービス拒否を軽減します。

クォータを使用して、テナントの支出に合わせてクラスターのリソースを割り当てることもできます。これは、KaaS シナリオで特に役立ちます。

### ポッドの優先度とプリエンプション
<a name="_pod_priority_and_preemption"></a>

Pod の優先度とプリエンプションは、他の Pod よりも Pod を重視する場合に役立ちます。例えば、ポッドの優先度では、顧客 A のポッドを顧客 B よりも高い優先度で実行するように設定できます。使用可能な容量が不足すると、スケジューラは顧客 B の優先度の低いポッドを削除して、顧客 A の優先度の高いポッドに対応します。これは、顧客がプレミアムの支払いを希望する SaaS 環境で特に便利です。

**重要**  
ポッドの優先度は、優先度の低い他のポッドに望ましくない影響を与える可能性があります。例えば、犠牲者ポッドは正常に終了されますが、PodDisruptionBudget は保証されません。これにより、ポッドのクォーラムに依存する優先度の低いアプリケーションが破損する可能性があります。[「優先の制限](https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#limitations-of-preemption)」を参照してください。

## コントロールの軽減
<a name="_mitigating_controls"></a>

マルチテナント環境の管理者としての主な懸念は、攻撃者が基盤となるホストにアクセスできないようにすることです。このリスクを軽減するには、次のコントロールを検討する必要があります。

### コンテナのサンドボックス実行環境
<a name="_sandboxed_execution_environments_for_containers"></a>

サンドボクシングは、各コンテナを独自の独立した仮想マシンで実行する手法です。ポッドサンドボックスを実行するテクノロジーには、[Firecracker](https://firecracker-microvm.github.io/) や Weave's [Firekube](https://www.weave.works/blog/firekube-fast-and-secure-kubernetes-clusters-using-weave-ignite) などがあります。

Firecracker を EKS でサポートされているランタイムにする作業の詳細については、https://threadreaderapp.com/thread/1238496944684597248.html を参照してください。

### オープンポリシーエージェント (OPA) とゲートキーパー
<a name="_open_policy_agent_opa_gatekeeper"></a>

 [Gatekeeper](https://github.com/open-policy-agent/gatekeeper) は、[OPA](https://www.openpolicyagent.org/) で作成されたポリシーを適用する Kubernetes アドミッションコントローラーです。OPA を使用すると、別のインスタンスまたは他のテナントよりも高い優先度でテナントからポッドを実行するポリシーを作成できます。一般的な OPA ポリシーのコレクションは、このプロジェクトの GitHub [リポジトリ](https://github.com/aws/aws-eks-best-practices/tree/master/policies/opa)にあります。

[CoreDNS の実験的な OPA プラグイン](https://github.com/coredns/coredns-opa)もあり、OPA を使用して CoreDNS から返されたレコードをフィルタリング/制御できます。

### キバーノ
<a name="_kyverno"></a>

 [Kyverno](https://kyverno.io) は、Kubernetes リソースとしてポリシーを使用して設定を検証、変更、生成できる Kubernetes ネイティブポリシーエンジンです。Kyverno は検証に Kustomize スタイルのオーバーレイを使用し、ミューテーションの JSON パッチと戦略的マージパッチをサポートし、柔軟なトリガーに基づいて名前空間間でリソースをクローンできます。

Kyverno を使用して、名前空間の分離、ポッドセキュリティやその他のベストプラクティスの適用、ネットワークポリシーなどのデフォルト設定の生成を行うことができます。このプロジェクトの GitHub [リポジトリ](https://github.com/aws/aws-eks-best-practices/tree/master/policies/kyverno)には、いくつかの例が含まれています。その他多くの は、Kyverno ウェブサイトの[ポリシーライブラリ](https://kyverno.io/policies/)に含まれています。

### テナントワークロードを特定のノードに分離する
<a name="_isolating_tenant_workloads_to_specific_nodes"></a>

テナントワークロードを特定のノードで実行するように制限することで、ソフトマルチテナンシーモデルの分離を強化できます。このアプローチでは、テナント固有のワークロードは、それぞれのテナント用にプロビジョニングされたノードでのみ実行されます。この分離を実現するために、ネイティブ Kubernetes プロパティ (ノードアフィニティ、テイントと許容範囲) を使用して、ポッドスケジューリングのために特定のノードをターゲットにし、他のテナントからのポッドがテナント固有のノードでスケジュールされないようにします。

#### パート 1 - ノードアフィニティ
<a name="_part_1_node_affinity"></a>

Kubernetes [ノードアフィニティ](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity)は、ノード[ラベル](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/)に基づいてスケジューリングするノードをターゲットにするために使用されます。ノードアフィニティルールでは、ポッドはセレクタ条件に一致する特定のノードに引き付けられます。以下のポッド仕様では、`requiredDuringSchedulingIgnoredDuringExecution`ノードアフィニティがそれぞれのポッドに適用されます。その結果、ポッドは というキー/値でラベル付けされたノードをターゲットにします`node-restriction.kubernetes.io/tenant: tenants-x`。

```
...
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: node-restriction.kubernetes.io/tenant
            operator: In
            values:
            - tenants-x
...
```

このノードアフィニティでは、ラベルはスケジューリング中に必要になりますが、実行時には必要ではありません。基になるノードのラベルが変更された場合、そのラベルが変更されてもポッドは削除されません。ただし、将来のスケジューリングに影響する可能性があります。

**警告**  
のラベルプレフィックス`node-restriction.kubernetes.io/`は、Kubernetes で特別な意味を持ちます。EKS クラスターに対して有効になっている [NodeRestriction](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) は、このプレフィックスを持つラベルadding/removing/updating`kubelet`することを に禁止します。攻撃者は、これらのラベルを変更`kubelet`できない`kubelet’s credentials to update the node object or modify the system setup to pass these labels into `kubelet`ため、 を使用できません。このプレフィックスをすべてのポッドからノードへのスケジューリングに使用すると、攻撃者がノードラベルを変更して別のワークロードセットをノードに引き付けるシナリオを防ぐことができます。

**Example**  
ノードアフィニティの代わりに、[ノードセレクタ](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector)を使用できます。ただし、ノードアフィニティはより表現力が高く、ポッドスケジューリング中により多くの条件を考慮できます。相違点とより高度なスケジューリングの選択肢の詳細については、[アドバンスト Kubernetes ポッドからノードへのスケジューリング](https://www.cncf.io/blog/2021/07/27/advanced-kubernetes-pod-to-node-scheduling/)に関するこの CNCF ブログ記事を参照してください。

#### パート 2 - テイントと許容範囲
<a name="_part_2_taints_and_tolerations"></a>

ポッドをノードに引き付けることは、この 3 つの部分からなるアプローチの最初の部分にすぎません。このアプローチを機能させるには、ポッドが承認されていないノードにポッドがスケジュールされないようにする必要があります。不要なポッドや不正なポッドを撃退するために、Kubernetes はノード[テイント](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)を使用します。テイントは、ポッドのスケジュールを妨げる条件をノードに配置するために使用されます。以下のテイントでは、 のキーと値のペアを使用します`tenant: tenants-x`。

```
...
    taints:
      - key: tenant
        value: tenants-x
        effect: NoSchedule
...
```

上記のノード の場合`taint`、テイントを*許容*するポッドのみをノードでスケジュールできます。承認されたポッドをノードにスケジュールできるようにするには、以下に示すように、それぞれのポッド仕様にテイント`toleration`への を含める必要があります。

```
...
  tolerations:
  - effect: NoSchedule
    key: tenant
    operator: Equal
    value: tenants-x
...
```

上記のポッドは、少なくともその特定のテイントのために、ノードでのスケジューリングを停止`toleration`されません。テイントは、ノードリソースのプレッシャーなど、特定の条件下でポッドスケジューリングを一時的に停止するために Kubernetes でも使用されます。ノードアフィニティ、テイント、許容度により、目的のポッドを特定のノードに効果的に引き付け、不要なポッドを反発できます。

**重要**  
特定の Kubernetes ポッドは、すべてのノードで実行する必要があります。これらのポッドの例は、[コンテナネットワークインターフェイス (CNI)](https://github.com/containernetworking/cni) と [kube-proxy](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/) [デーモンセット](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/)によって開始されるポッドです。そのために、これらのポッドの仕様には、さまざまなテイントを許容するための非常に寛容な許容範囲が含まれています。これらの許容範囲を変更しないように注意してください。これらの許容値を変更すると、クラスターオペレーションが正しくない可能性があります。さらに、[OPA/Gatekeeper](https://github.com/open-policy-agent/gatekeeper) や [Kyverno](https://kyverno.io/) などのポリシー管理ツールを使用して、不正なポッドがこれらの許容値を使用することを防ぐ検証ポリシーを記述できます。

#### パート 3 - ノード選択のポリシーベースの管理
<a name="_part_3_policy_based_management_for_node_selection"></a>

CICD パイプラインでのルールの適用など、ポッド仕様のノードアフィニティと許容範囲の管理に役立つツールがいくつかあります。ただし、分離の適用は Kubernetes クラスターレベルで行う必要があります。この目的のために、ポリシー管理ツールを使用して、リクエストペイロードに基づいてインバウンド Kubernetes API サーバーリクエスト*を変更*し、上記のそれぞれのノードアフィニティルールと許容値を適用できます。

例えば、*tentains-x* 名前空間宛てのポッドには、*tentens-x* ノードでスケジュールできるように、正しいノードのアフィニティと許容値*でスタンプ*を付けることができます。Kubernetes [Mutating Admission Webhook](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook) を使用して設定されたポリシー管理ツールを使用して、ポリシーを使用してインバウンドポッドの仕様を変更できます。ミューテーションは、必要なスケジューリングを可能にするために必要な要素を追加します。ノードアフィニティを追加する OPA/Gatekeeper ポリシーの例を以下に示します。

```
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: mutator-add-nodeaffinity-pod
  annotations:
    aws-eks-best-practices/description: >-
      Adds Node affinity - https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    namespaces: ["tenants-x"]
  location: "spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms"
  parameters:
    assign:
      value:
        - matchExpressions:
          - key: "tenant"
            operator: In
            values:
            - "tenants-x"
```

上記のポリシーは Kubernetes API サーバーリクエストに適用され、ポッドを *tenants-x* 名前空間に適用します。このポリシーは`requiredDuringSchedulingIgnoredDuringExecution`ノードアフィニティルールを追加して、ポッドが `tenant: tenants-x`ラベルを持つノードに引き付けられるようにします。

以下に示す 2 番目のポリシーでは、ターゲット名前空間とグループ、種類、バージョンの同じ一致基準を使用して、同じポッド仕様に許容範囲を追加します。

```
apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: mutator-add-toleration-pod
  annotations:
    aws-eks-best-practices/description: >-
      Adds toleration - https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    namespaces: ["tenants-x"]
  location: "spec.tolerations"
  parameters:
    assign:
      value:
      - key: "tenant"
        operator: "Equal"
        value: "tenants-x"
        effect: "NoSchedule"
```

上記のポリシーはポッドに固有です。これは、ポリシーの 要素の変更された`location`要素へのパスが原因です。デプロイやジョブのリソースなど、ポッドを作成するリソースを処理する追加のポリシーを作成できます。リストされたポリシーやその他の例は、このガイドのコンパニオン [GitHub プロジェクト](https://github.com/aws/aws-eks-best-practices/tree/master/policies/opa/gatekeeper/node-selector)で確認できます。

これらの 2 つのミューテーションの結果、ポッドは目的のノードに引き付けられますが、同時に特定のノードテイントによってリピートされません。これを検証するには、2 つの`kubectl`呼び出しからの出力スニペットを表示して、 というラベルの付いたノードを取得し`tenant=tenants-x`、 `tenants-x`名前空間のポッドを取得します。

```
kubectl get nodes -l tenant=tenants-x
NAME
ip-10-0-11-255...
ip-10-0-28-81...
ip-10-0-43-107...

kubectl -n tenants-x get pods -owide
NAME                                  READY   STATUS    RESTARTS   AGE   IP            NODE
tenant-test-deploy-58b895ff87-2q7xw   1/1     Running   0          13s   10.0.42.143   ip-10-0-43-107...
tenant-test-deploy-58b895ff87-9b6hg   1/1     Running   0          13s   10.0.18.145   ip-10-0-28-81...
tenant-test-deploy-58b895ff87-nxvw5   1/1     Running   0          13s   10.0.30.117   ip-10-0-28-81...
tenant-test-deploy-58b895ff87-vw796   1/1     Running   0          13s   10.0.3.113    ip-10-0-11-255...
tenant-test-pod                       1/1     Running   0          13s   10.0.35.83    ip-10-0-43-107...
```

上記の出力からわかるように、すべてのポッドは というラベルの付いたノードでスケジュールされます`tenant=tenants-x`。簡単に言うと、ポッドは目的のノードでのみ実行され、他のポッド (必要なアフィニティと許容値なし) は実行されません。テナントワークロードは効果的に分離されます。

変更後のポッド仕様の例を以下に示します。

```
apiVersion: v1
kind: Pod
metadata:
  name: tenant-test-pod
  namespace: tenants-x
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: tenant
            operator: In
            values:
            - tenants-x
...
  tolerations:
  - effect: NoSchedule
    key: tenant
    operator: Equal
    value: tenants-x
...
```

**重要**  
Kubernetes API サーバーリクエストフローに統合されているポリシー管理ツールは、変更と検証アドミッションウェブフックを使用して、指定された期間内に API サーバーのリクエストに応答するように設計されています。これは通常 3 秒以下です。ウェブフック呼び出しが設定された時間内にレスポンスを返さない場合、インバウンド API サーバーリクエストのミューテーションや検証が発生する場合と発生しない場合があります。この動作は、アドミッションウェブフック設定がフェ[イルオープンまたはフェイルクローズ](https://open-policy-agent.github.io/gatekeeper/website/docs/#admission-webhook-fail-open-by-default)に設定されているかどうかに基づいています。

上記の例では、OPA/Gatekeeper 用に記述されたポリシーを使用しました。ただし、ノード選択のユースケースを処理する他のポリシー管理ツールもあります。例えば、この [Kyverno ポリシー](https://kyverno.io/policies/other/add_node_affinity/add_node_affinity/)を使用してノードアフィニティミューテーションを処理できます。

**注記**  
正しく動作している場合、ポリシーを変更すると、インバウンド API サーバーのリクエストペイロードに必要な変更が反映されます。ただし、変更の保持を許可する前に、ポリシーの検証を含めて、必要な変更が行われることを確認する必要があります。これは、tenant-to-node分離にこれらのポリシーを使用する場合に特に重要です。また、*監査*ポリシーを含めて、不要な設定がないかクラスターを定期的にチェックすることをお勧めします。

### リファレンス
<a name="_references"></a>
+  [k-rail](https://github.com/cruise-automation/k-rail) 特定のポリシーを適用してマルチテナント環境を保護するように設計されています。
+  [Amazon EKS を使用した MultiTenant SaaS アプリケーションのセキュリティプラクティス](https://d1.awsstatic.com/whitepapers/security-practices-for-multi-tenant-saas-apps-using-eks.pdf) 

## ハードマルチテナンシー
<a name="_hard_multi_tenancy"></a>

ハードマルチテナンシーは、テナントごとに個別のクラスターをプロビジョニングすることで実装できます。これはテナント間で非常に強力な分離を提供しますが、いくつかの欠点があります。

まず、テナントが多い場合、このアプローチはすぐに高価になる可能性があります。クラスターごとにコントロールプレーンのコストを支払う必要があるだけでなく、クラスター間でコンピューティングリソースを共有することはできません。これにより、最終的に断片化が発生し、クラスターのサブセットが十分に活用されず、他のサブセットが過剰に活用されます。

次に、これらのすべてのクラスターを管理するための特別なツールを購入または構築する必要があります。時間が経つと、数百または数千のクラスターを管理するだけでは扱いにくくなる可能性があります。

最後に、テナントごとのクラスターの作成は、名前空間の作成と比較して遅くなります。ただし、規制の厳しい業界や強力な分離が必要な SaaS 環境では、ハードテナンシーアプローチが必要になる場合があります。

## 今後の方向性
<a name="_future_directions"></a>

Kubernetes コミュニティは、ソフトマルチテナンシーの現在の欠点とハードマルチテナンシーの課題を認識しています。[Multi-Tenancy Special Interest Group (SIG)](https://github.com/kubernetes-sigs/multi-tenancy) は、階層名前空間コントローラー (HNC) や仮想クラスターなど、いくつかの冪定プロジェクトを通じてこれらの欠点に対処しようとしています。

HNC 提案 (KEP) では、〔ポリシー] オブジェクト継承を使用して名前空間間に親子関係を作成する方法と、テナント管理者がサブ名前空間を作成する機能について説明します。

仮想クラスター提案では、クラスター内のテナント (Kubernetes on Kubernetes とも呼ばれます) ごとに、API サーバー、コントローラーマネージャー、スケジューラなど、コントロールプレーンサービスの個別のインスタンスを作成するメカニズムについて説明します。

[マルチテナンシーベンチマーク](https://github.com/kubernetes-sigs/multi-tenancy/blob/master/benchmarks/README.md)提案は、分離とセグメンテーションに名前空間を使用してクラスターを共有するためのガイドラインと、ガイドラインへの準拠を検証するためのコマンドラインツール [kubectl-mtb](https://github.com/kubernetes-sigs/multi-tenancy/blob/master/benchmarks/kubectl-mtb/README.md) を提供します。

## マルチクラスター管理ツールとリソース
<a name="_multi_cluster_management_tools_and_resources"></a>
+  [バンザイ](https://banzaicloud.com/)雲 
+  [コマンダー](https://d2iq.com/solutions/ksphere/kommander) 
+  [レンズ](https://github.com/lensapp/lens) 
+  [Nirmata](https://nirmata.com) 
+  [Rafay](https://rafay.co/) 
+  [ランチャー](https://rancher.com/products/rancher/) 
+  [ウィーブフラックス](https://www.weave.works/oss/flux/) 