アカウント ログイン

Kubernetes Operator とは?

Kubernetes Operator は、Kubernetes アプリケーションをパッケージ化し、デプロイし、管理する手段です。Kubernetes アプリケーションはいずれも Kubernetes にインストールされ、Kubernetes API を使用して管理されます。Operator は、人間のオペレーターに代わってアプリケーションやサービスのライフサイクルの管理を自動化し、プラットフォームを設定する部品の管理からマネージドサービスとして提供されるアプリケーションまで、スタックのあらゆるレベルで自動化する能力を提供します。

エンジニアリングチームは Operator の機能を使用できます。これにより、Kubernetes オブジェクトで設定をネイティブに公開し、より頻繁で安定した更新を可能にすることで、自動化管理が可能になります。プラットフォームの管理における Operator 自動化の利点に加え、Red Hat OpenShift では、クラスタ上で動作する Operator の検索、インストール、管理が容易になります。

Red Hat OpenShift での Operator の使用

OpenShift は、ハイブリッドクラウドのデプロイメントを管理するためのフルスタック自動化オペレーションを備えたエンタープライズ Kubernetes プラットフォームです。

Red Hat OpenShift に含まれるのは、さまざまなソフトウェアベンダーやオープンソースプロジェクトによるオペレーターのレジストリである OperatorHub が組み込まれています。OperatorHub 内では、Red Hat OpenShift で動作することが確認され、ライフサイクル管理を容易にするためにパッケージ化されたオペレーターのライブラリを参照およびインストールすることができます。

OpenShift では、オペレーターを管理する仕組みとして、目的に応じて 2 種類のシステムを用意しています。

  • クラスター機能を実行するために、クラスタバージョンオペレータ (CVO) によって管理される プラットフォームオペレータ がデフォルトでインストールされています。

  • Operator Lifecycle Manager (OLM) で管理されている アドオンオペレーター は、ユーザーがアクセスしてアプリケーションで実行できるように設定できます。

さらに、適切な特権を持つユーザーは、YAML ファイルやヘルムチャートを使用するなど、他の手段でオペレーターを管理することができます。

Operator のセキュリティが重要な理由

実稼動環境でのデプロイに Operator を使用するエンジニアリングチームが増えています。Operator の潜在能力はまだ十分に発揮されていません。しかし、開発プロセスのできるだけ早い段階で、より安全なコードと手法を組み込むことの利点を見失わないようにすることが重要です。

オペレーターのための優れたセキュリティ対策

cluster-scope と namespace-scope のパーミッションの最小化

Operator には、以下の 2 つのタイプがあります。

  • namespace-scoped: オペレーターはネームスペース内のリソースを監視および管理します。これを行うには、ネームスペース内のパーミッションが必要です。

    • この中には、サブタイプがあります。

      • 開発者が決めた、単一の命名済み名前空間

      • インストール時に提供される単一のネームスペース

      • 複数の名前空間 (例: OperatorGroup で MultiNamespace インストールモード型を使用する)。

  • cluster-scoped: クラスタ内の全名前空間のリソースを監視管理します。そのために、クラスタスコープのパーミッションを必要とします

一般的には、最小特権の原則 (PoLP) に従って、Operator の機能を維持したまま、可能な限りアクセスを制限する必要があります。Operator のサービスアカウントと必要なロールおよびクラスタロールを結びつけるロールバインディングおよびクラスタロールバインディングを作成することによって、パーミッションを付与することができます。これは、Operator Lifecycle Manager (OLM) バンドル展開アーキテクチャを使用して実現することができます。

Operator バンドルは Operator イメージ自体とは別に、Operator に関するメタデータを保持するための OLM 規定のフォーマットです。メタデータには、Kubernetes が Operator を使用するために知る必要のあるすべての情報、つまり、Deploying Operators with OLM bundles で説明したカスタムリソース定義 (CRD)、ロールベースのアクセス制御 (RBAC) のロールと必要なバインディング、依存関係ツリー、その他の情報などが含まれています。

OLM を使用する利点は、Operator のインストールと実行に必要な権限を管理できる点です。OLM は cluster-admin ロールを使用してインストールを行い、インストール時間の要件を分離します。例えば、APIService と CustomResourceDefinition リソースは常に OLM が cluster-admin ロールを使用して作成するため、全体のパーミッション部分の処理を削減することができます。

OLM を使用して、クラスタ管理者は、Operator グループにサービスアカウントを指定し、グループに関連付けられたすべての Operator がサービスアカウントに付与された特権で展開および実行されるように選択することができます。Operator グループに関連付けられたサービスアカウントには、これらのリソースを作成するための権限を付与できません。この Operator グループ に関連付けられる Operator は、指定されたサービスアカウントに付与されるパーミッションに制限されます。Operator がサービスアカウントの範囲外のパーミッションを要求する場合、インストールは適切なエラーを出して失敗します。

cluster-scope パーミッションの使用を減らします。

cluster-scoped Operator の使用は正当化される必要があります。必要ない場合は、必要最小限の権限で namespaced-scoped Operator を実行することをお勧めします。

cluster-scoped Operator は、クラスタロールとクラスタロールバインディングを使用して取得したアクセス権を使用して、コントロールプレーンを含むクラスタ全体のリソースにアクセスする必要があります。

namespace-scoped Operator では単一の名前空間のリソースへのアクセスのみが必要で、これらのパーミッションはロールおよびロールバインディングを使用して取得できます。例外として、namespace-scoped Operator が、クラスタが指定されたリソースである CustomResourceDefinition (CRD) を作成する必要がある場合があります。

Operator に与えられた入力に基づいて定義が変更されない静的な cluster-scope リソースがある場合は、それらのリソースの作成を Operator Lifecycle Manager (OLM) カタログに移行することができます。例えば、CRD の作成は、Operator のライフサイクルを通じて変化しないので、Operator から OLM に移行することができます。

RBAC パーミッション

Kubernetes と OpenShift の両プラットフォームは、ロールベースアクセスコントロール (RBAC) による権限付与を提供しています。セキュリティコンテキスト は、Kubernetes における Pod やコンテナの定義に不可欠な要素です。これは、セキュリティコンテキスト制約 (Security Context Constraint、SCC)と呼ばれる OpenShift のセキュリティ機能とは異なることに注意してください。

Kubernetes Operator は、Operator に付与される権限も定義しており、一般的には role.yaml という YAML 定義で定義します。ロールは名前空間レベルで割り当てられるため、特権の拡大は本質的に名前空間自体によって制限されます。ただし、ClusterRole はクラスタ全体に適用されるため、より慎重に確認する必要があります。

特権がエスカレートする可能性があるのは、非特権ユーザー (system:authenticated ロールを持つ) が、Operator が使用するサービスアカウントトークンにアクセスした場合です。このリスクを減らす一般的な方法は、Operator をその Operand とは別の名前空間に展開し、非特権ユーザーがそのシークレットを読むアクセス権を持たないようにします。あるいは、非特権ユーザーと共有する名前空間に展開した場合は、それらのユーザーはその名前空間のシークレットを読むアクセス権を持たないようにすることです。Operator は共有名前空間にデプロイされないようにすることが推奨されます(特に非特権ユーザーアクセスを許可する名前空間)。

コードレビューでは、RBAC ロールを利用して余分な特権を得ることができないかどうかを確認することをお勧めします。

気をつけるべき例

  • Bind 動詞は、Roles または ClusterRoles に適用することができ、プリンシパルは (クラスタ) ロールバインディングの作成に関する一般的な制限を回避することができます。この制限により、ロールバインディングを作成できるユーザーが、クラスタ管理者などの高い権限のロールにバインドして権限をエスカレートすることを阻止できます。この制限は、Kubernetes のドキュメント Restrictions on role binding creation or update に記載されています。

  • クラスタロールの権利をエスカレート: Escalate は Kubernetes RBAC チェックをバイパスし、ロールやクラスタロールを作成できるユーザーがこれらのオブジェクトを作成 (または編集) して、所有している以上の権限を持つことができないようにするものです。

  • Operator がクラスタ上で実行する可能性のあるコンテナに対して必要なアクションの範囲を縮小するために、複数のロール 記述する必要があります。たとえば、起動時に TLS シークレットを生成するコンポーネントがある場合、単一の強力なサービスアカウントを使用するよりも、シークレットの作成は許可するがリストは許可しないロールの方がより安全です。

  • cluster-admin を付与すると、cluster-admin 自身が SCC を更新/変更できるようになります。

  • 指定の SCC の使用権があり、かつ「ポッドの作成」が可能であれば、SCC が許可する全範囲を取得するために新しいポッドを作成することができます。

  • RBAC の編集を許可する RBAC がある場合は、独自の制限を編集できます。

    • 以下に例を示します。

resources:
- roles
- rolebindings
verbs:
- patch
- create

要求されたときにロールを与えることで、特権のないユーザーに特権のある名前空間へのアクセス許可を与えることができるようになる可能性があります。(注: デフォルトでは、Operator は自身が持つ他者への権限付与にのみ制限されます)。

ワイルドカードの回避

RBAC の定義では、下のイメージのようにワイルドカード文字を使用するのではなく、各動詞やリソースを明示的にリストアップするのがよいでしょう。これにより、各項目について、どこでどのようなパーミッションが必要なのか、あるいは初期の開発時に誤って取得したものなのか、より簡単に確認することができます。

例えば、動詞の項目で「*」を使う代わりに、get、list、watch のように完全な形で列挙することができます。Operator が編集するリソースの名前を知っていれば、get/edit だけに限定することができ、しばしば list が不要になります。

リストを明示することで、将来的に「*」が変更され、現在存在しない項目と一致するようになった場合にも、権限を保護することができます。

RBAC の使用によるパーミッションの定義および適用

クラスタロール、ロール、クラスタロールのバインディング、ロールバインディング、ユーザー、グループ、およびサービスアカウントの関係を以下に示します。

Kubernetes Operators - Figure 1 default cluster roles

図 1: デフォルトのクラスタロール

Descoped Operator

Operator は名前空間のサービスアカウントで実行されるため、その名前空間にワークロードを作成する能力を持つ人は、オペレーターの権限にエスカレートすることができます。これらの懸念に対応するために、スコープオペレーターの概念が OperatorGroup オブジェクトで導入されました。OperatorGroup は、インストールされたすべての Operator が同じスコープを共有するクラスタ内の名前空間のセットを指定します。Operator Lifecycle Manager (OLM) は、名前空間内の 1 つのオペレーターのみが特定の CRD を所有するようにし、衝突の問題を回避します。

この問題は、クラスタの API がクラスタスコープにあることです。これらは、検出により、表示したいユーザーに対して表示されます。特定の Group、Version、Kind (GVK) に同意する Operator も、これらのオブジェクトがクラスタで許可される方法や、API バージョン間の変換方法に違いが生じる可能性があります。つまり、複数の「opinion」がクラスタに存在する可能性が高まります。

Operator Descoping Plan の記事では、これについて記述しています。

Pod およびコンテナの securityContext と SCC (Security Context Constraints)

サードパーティのアプリケーションをコンテナ化する場合は、そのアプリケーションの期待に応えて、特定の UID で実行することが必要になる場合があります (おそらく root で実行することもあるでしょう)。コンテナネイティブになるように作成されたオペレーターの場合は、決して UID を期待せず、OpenShift クラスタが、オペレーターが実行するネームスペースに割り当てる慣習的な億超えの高い UID を受け入れる必要があります。

  • Containerfile に数値の USER を設定してデフォルトを回避したり、予想されるユーザーに uid=0 があることを想定します。

  • 共有ファイルのパーミッション管理には、ユーザー ID の代わりにグループ ID の権限を使用します。

同様に、hostPath ボリュームを使用すると、ホストノード上のファイルがコンテナからアクセスできるようになります。コンテナが安全に設定されておらず、侵害された場合、攻撃者はホストとそのホスト上で動作する他のコンテナを攻撃しようとする可能性があります。

hostPath の場合:

  • オペレータは、ホストパスがコントロールプレーン自体の一部を設定していない限り、決してホストパスを必要とすべきではありません。

その他のデプロイメントに関する推奨事項:

  • readOnlyRootFilesystem: TRUE に設定

    • ローカルファイルをルートファイルシステムに書き込まないようにします。代わりに /tmp または emptyDir を使用します。PID ファイルおよび STDOUT に移動していないログ出力に注意してください。

  • runAsNonRoot: TRUE に設定

    • これは、podSpec または containerSpec のセキュリティコンテキストのいずれかで設定できます。これを有効にすると、その他の状況で uid=0 で実行している可能性がある場合、コンテナは実行を拒否します。

  • automount service account token: FALSE に設定

    • デフォルトでは、サービスアカウントトークンはコンテナ内のファイルとしてマウントされます。Operator は通常、機能するためにアクセスする必要のある SA があります (つまり、この TRUE を設定します)。しかし、オペレーターが作成する Pod には、この設定を false にすることで保護を強化できることがあります。

OpenShift Security Context Constraints (SCC) は、クラスタに対して許可される Pod を制限するゲートキーパーです。Operator プロセスもクラスタ内の Pod として実行されるため、同じ概念を使用して、Operator コンテナのセキュリティ態勢も強化することができます。

Udica ツールが作成され、カスタム SCC に関連付けられるカスタム SELinux ポリシーの作成が単純化されました。

継続的なセキュリティスキャン

継続的にスキャンすることで、脆弱性を特定し、Go、Kubernetes、Operator コンテナのベースイメージの最新のセキュリティバグフィックスを検出できます。

OpenShift で実行されている、Red Hat Quay レジストリから引き出されたコンテナイメージについては、Operator を使用してそれらのイメージの脆弱性を一覧表示することができます。Container Security Operator を OpenShift に追加して、選択された名前空間に追加されるイメージの脆弱性レポートを提供できます。

Red Hat Quay のコンテナイメージスキャンは、Clair-security scanner によって実行されます。Red Hat Quay では、Clair は RHEL、CentOS、Oracle、Alpine、Debian、および Ubuntu のオペレーティングシステムソフトウェアでビルドされたイメージの脆弱性を検索し、報告することができます。

デプロイメントの場所

Operator が実行される場所について状況にもよりますが、適切な場所で Operator を実行することをお勧めします。コントロールプレーンの一部を構成する Operator の場合は、Tolerations を使用してコントロールプレーンノードで実行するようにスケジュールできます。

Operator と Operand がネームスペース間で分割されている場合でも、Operator 自体が kube API との対話を実行するために高い特権を持つサービスアカウントを持っている場合があるため、ワーカーノード上で実行すると、そのワーカーノードの侵害によりサービスアカウントの認証情報が破られる場合があります。そのため、ノードや名前空間によるワークロードの分離が有益です。

役に立つリソース

参考資料


About the authors

Working as a Threat Modeler on the Secure Development Architecture Validation team within Product Security's Secure Engineering group since 2019.

Read full bio

Dave Baker has been with Red Hat since 2017.  He's currently working as a Design Architect in the Secure Engineering team within Product Security, and has spent the last years in various security related roles helping to protect Red Hat OpenShift Container Platform and many other products.

Read full bio

Joined Red Hat in 2017. Interested in identity management, all things security, automation and open source.

Read full bio

Florencio has had cybersecurity in his veins since he was a kid. He started in cybersecurity around 1998 (time flies!) first as a hobby and then professionally. His first job required him to develop a host-based intrusion detection system in Python and for Linux for a research group in his university. Between 2008 and 2015 he had his own startup, which offered cybersecurity consulting services.

Read full bio