コンテンツにスキップ

OpenPolicyAgent@CNCF

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. OpenPolicyAgentの仕組み

アーキテクチャ

OpenPolicyAgentは、OpenPolicyエージェント、.regoファイル、DB、といったコンポーネントから構成される。

open-policy-agent_architecture


OpenPolicyエージェント

DBからアカウント情報を読み出し、認可処理を実行する。

この時、.regoファイルのロジックに基づいて、boolean型値を返却する。

返却されたboolean型値を使用して、リクエストの送信元 (例:アプリケーション、kube-apiserver) で認可スコープ内の処理を実行する。

open-policy-agent


.regoファイル

認可スコープのロジックを定義する。


DB

アカウント情報を.json形式、認可スコープ定義を.rego形式で、保管する。


02. ユースケース

アプリケーションの認可サービスとして

▼ アプリケーションの認可サービスとは

アプリケーションの認可スコープ定義の責務を認可サービスとして切り分ける。

アプリケーションはOpenPolicyAgentにリクエストを送信し、OpenPolicyAgentは認可スコープに応じてboolean型値を返却する。

返却されたboolean型値を使用して、アプリケーションは認可スコープ内の処理を実行する。

▼ アカウント情報の作成

(1)

アカウント情報を.json形式で作成する。

ここでは、各アカウントが一般社員または管理職のいずれかであるかを定義している。

# subordinates.jsonファイル
{"alice": ["bob"], "bob": [], "charlie": ["david"], "david": []}
(2)

アプリケーションは、OpenPolicyエージェントにアカウント情報を送信し、アカウント情報をDBに作成する。

$ curl \
    -X PUT \
    -H 'Content-Type:application/json' \
    --data-binary @subordinates.json \
    127.0.0.1:8181/v1/data/subordinates

▼ 認可スコープの定義

(3)

認可スコープ定義のロジックを.rego形式で作成する。

package httpapi.authz

# 社員のアカウント情報をインポートする。
import data.subordinates as subord

default allow = false

# 一般社員は、自身の給与のみで参照権限を持つ (trueを返却する) 
allow {
  some username
  input.method == "GET"
  input.path = ["finance", "salary", username]
  input.user == username
}

# 管理職は、自身と部下社員の給与で参照権限を持つ (trueを返却する) 
allow {
  some username
  input.method == "GET"
  input.path = ["finance", "salary", username]
  subord[input.user][_] == username
}
(4)

アプリケーションは、OpenPolicyエージェントに.regoファイルを送信し、認可スコープ定義をDBに作成する。

$ curl \
    -X PUT \
    -H 'Content-Type: text/plain'\
    --data-binary @httpapi_authz.rego \
    127.0.0.1:8181/v1/policies/httpapi_authz

▼ 認可スコープのリクエスト

(5)

認可スコープを取得するためのリクエストを.json形式で作成する。

実際は、aliceというアカウントがデータを参照できるかどうかを取得するために、アプリケーションがリクエストを作成する。

# request.jsonファイル
{
  # リクエストの内容
  "input": {
      # GETメソッド
      "method": "GET",
      # パス
      "path": ["finance", "salary", "alice"],
      # アカウント名
      "user": "alice",
    },
}
(6)

アプリケーションは、aliceアカウントの参照権限の有無をOpenPolicyエージェントにリクエストを送信する。

OpenPolicyエージェントは、アプリケーションにtrueを返却する。

$ curl \
    -X POST \
    -H 'Content-Type:application/json' \
    --data-binary @request.json \
    127.0.0.1:8181/v1/data/httpapi/authz/allow | jq .

{
  "result": "true"
}


KubernetesのGatekeeperとして

▼ Gatekeeperとは

内部的にOpenPolicyAgentを使用して、Kubernetesのマニフェストを検証する。

kube-apiserverのvalidating-admissionステップ時に、GatekeeperのwebhookサーバーにAdmissionReviewのリクエストが送信され、Gatekeeperの持つOpenPolicyAgentの処理を発火させる。

そのため、GitOpsのCDパイプライン上にバリデーションを実行できる。

kubernetes_open-policy-agent

▼ gatekeeper-validating-webhook-configuration

Podの作成/更新時にwebhookサーバーにリクエストを送信できるように、ValidatingWebhookConfigurationでValidatingWebhookアドオンを設定する。

.webhooks.failurePolicyキーで設定している通り、webhookサーバーのコールに失敗した場合は、無視してkube-apiserverの処理を続ける。

そのため、Gatekeeperが起動に失敗しても、Podが中止されることはない。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: gatekeeper-validating-webhook-configuration
  labels:
    gatekeeper.sh/system: "yes"
webhooks:
  # webhook名は完全修飾ドメイン名にする。
  - name: validation.gatekeeper.sh
    admissionReviewVersions: ["v1", "v1beta1"]
    clientConfig:
      # webhookサーバーをCluster内部に自作する場合は、webhookサーバーに証明書バンドルを登録する。
      caBundle: Ci0tLS0tQk...
      # Webhookの前段にあるServiceの情報を登録する。
      service:
        name: gatekeeper-webhook-service
        namespace: gatekeeper-system
        # エンドポイント
        path: /v1/admit
        port: 443
    failurePolicy: Ignore
    matchPolicy: Exact
    namespaceSelector:
      matchExpressions:
        - key: admission.gatekeeper.sh/ignore
          operator: DoesNotExist
    objectSelector: {}
    # validating-admissionステップ発火条件を登録する。
    rules:
      - apiGroups: ["*"]
        apiVersions: ["*"]
        operations: ["CREATE", "UPDATE"]
        resources: ["*"]
        scope: "*"
    sideEffects: None
    timeoutSeconds: 3
    # webhook名は完全修飾ドメイン名にする。
  - name: check-ignore-label.gatekeeper.sh
    admissionReviewVersions: ["v1", "v1beta1"]
    clientConfig:
      # webhookサーバーをCluster内部に自作する場合は、webhookサーバーに証明書バンドルを登録する。
      caBundle: Ci0tLS0tQk...
      # Webhookの前段にあるServiceの情報を登録する。
      service:
        name: gatekeeper-webhook-service
        namespace: gatekeeper-system
        # エンドポイント
        path: /v1/admitlabel
        port: 443
    # webhookサーバーのコールに失敗した場合の処理を設定する。
    failurePolicy: Fail
    matchPolicy: Exact
    namespaceSelector: {}
    objectSelector: {}
    # validating-admissionステップ発火条件を登録する。
    rules:
      - apiGroups: [""]
        apiVersions: ["*"]
        operations: ["CREATE", "UPDATE"]
        resources: ["namespaces"]
        scope: "*"
    sideEffects: None
    timeoutSeconds: 3