$30 off During Our Annual Pro Sale. View Details »

Open Policy Agent / Gatekeeper 勉強会

Open Policy Agent / Gatekeeper 勉強会

Akihiro Ikezoe

August 26, 2019
Tweet

More Decks by Akihiro Ikezoe

Other Decks in Technology

Transcript

  1. Open Policy Agent
    Gatekeeper
    勉強会
    2019/08/26 (2019/11/24改訂)
    池添 明宏

    View Slide

  2. 目次
    • OpenPolicyAgent とは
    • Document
    • Rego
    • Gatekeeper とは
    • ポリシーの作り方
    • 機能紹介
    2

    View Slide

  3. Open Policy Agent とは
    • 軽量な汎用ポリシーエンジン
    • ポリシーに基づいて入力データの検証をおこなう
    • 特徴
    • 宣言的な記述でポリシーの読み書きがしやすい
    • コンパイルし直すことなくポリシーの変更が可能
    3

    View Slide

  4. 何に使えるの?
    • 例えば Kubernetes において、RBAC よりも柔軟なルールを適用でき
    る。
    • 例:
    • Pod に resource フィールドの指定を強制する
    • 利用可能なコンテナレジストリを制限する
    • 特定のユーザーに一部のリソースへのアクセスを制限する
    4

    View Slide

  5. Data & Policy
    5
    • Data (Document)
    • サービスやユーザーが用意するデータ
    • JSON 形式
    • Policy (Rule)
    • データに適用する検証ルール
    • Rego という独自言語で定義
    出展: https://www.openpolicyagent.org/docs/latest/how-does-opa-work/

    View Slide

  6. Document の種別
    • Base Documents
    • サービスやユーザーが用意した
    データ
    • Virtual Documents
    • Rule を適用した結果データ
    • Virtual Documents にさらに
    Rule を適用することも可能
    6
    出展: https://www.openpolicyagent.org/docs/latest/how-does-opa-work/

    View Slide

  7. Documents の構造
    • data
    • 検証に利用する静的なデータ
    • Rule を適用した結果データ
    • input
    • 検証対象の入力データ
    7
    出展: https://www.openpolicyagent.org/docs/latest/how-does-opa-work/

    View Slide

  8. Rule から Document へのアクセス
    • import で Document にアクセス
    できる
    • 例えば opa.examples.allow とい
    うルールを適用した結果の Virtual
    Document は、data.opa.example
    s.allow に入っている。
    8
    import data.opa.examples.allow
    import data.servers
    rule {
    server := servers[_]
    input.server == server
    allow[server]
    }

    View Slide

  9. Rules
    • Rego という独自言語でデータの検証ルールを記述する
    • Rego
    • Datalog という Prolog 系言語をインスパイア
    • 宣言的な記述が可能
    • The Rego Playground で試してみよう
    • https://play.openpolicyagent.org/
    9

    View Slide

  10. Rego による Rule の定義
    10
    # BODYの条件を満たした場合
    # HEADの値を返す
    rule_name {

    }
    # 条件を満たさなかった場合
    # undefinedを返す
    # 配列の場合は空配列を返す
    # HEADの省略は =trueと同じ
    rule1 {
    input.x < input.limit
    }
    # 固定値を返す
    rule2 = "abc" {
    input.x < input.limit
    }
    # 変数を返すことも可能
    rule3 = x {
    x := input.x
    x < input.limit
    }

    View Slide

  11. AND 条件と OR 条件
    11
    # 羅列するとAND条件
    rule_name {



    }
    # OR条件は同一名のルールを
    # 複数個用意する
    rule_name {

    }
    rule_name {

    }

    View Slide

  12. Go 言語と比較してみる
    12
    # Rego
    default allow = false
    allow = true {
    input.size != 0
    input.size < data.limit
    }
    # Go
    func allow() bool {
    if input.size == 0 {
    return false
    }
    if input.size >= data.limit {
    return false
    }
    return true
    }

    View Slide

  13. else
    • 同一名の複数ルールは適用順序が考
    慮されない。矛盾したルールは記述
    することができない。
    • 順序を考慮する場合は else キーワー
    ドを利用する。
    13
    rule_name {

    } else {

    }

    View Slide

  14. 繰り返し
    14
    containers = {
    "ap": {
    "image": "ubuntu:18.04"
    },
    "db": {
    "image": "mysql:latest"
    },
    }
    # latestイメージを抽出してkeyを返す
    rule[key] = image {
    image := containers[key].image
    endswith(image, ":latest")
    }
    numbers = [1, 2, 3, 4, 5]
    # 偶数だけを抽出
    rule[x] {
    x := numbers[_]
    x % 2 == 0
    }

    View Slide

  15. For Any, For All
    15
    # For All
    # 条件を逆にして否定する
    positive {
    not isNegative
    }
    isNegative {
    x := numbers[_]
    x < 0
    }
    # 内包表記
    positives {
    negative :=
    [x | x := numbers[_]; x < 0]
    count(negatives) == 0
    }
    # For Any
    numbers = [1, 2, 3, 4, 5]
    # 1つでも条件に一致すればtrue
    rule {
    x := numbers[_]
    x >= 0
    }

    View Slide

  16. Go 言語と比較してみる
    16
    # Rego
    images = [
    "quay.io/cybozu/ubuntu",
    "docker.io/nginx",
    "localhost/nginx"
    ]
    repos = [
    "quay.io",
    "docker.io"
    ]
    rule[img] {
    img := images[_]
    rep := repos[_]
    startswith(img, rep)
    }
    # Go
    func rule() []string {
    var result []string
    for _, img := range images {
    for _, rep := range repos {
    if strings.HasPrefix(img, rep) {
    result = append(result, img)
    }
    }
    }
    return result
    }

    View Slide

  17. 関数定義
    • ルールと似たような記法で関数
    を定義することができる。
    • 関数は引数を受け取ることがで
    きる。
    • ルールのように Virtual
    Document は生成されない
    17
    starts_with_foo(s) {
    startswith(s, "foo")
    }
    remove_prefix_foo(s) = r {
    starts_with_foo(s)
    r := substring(s, 3, -1)
    }

    View Slide

  18. 組み込み関数
    • 集計: count(), sum(), sort(), all(), any()
    • 文字列: contains(), startswidt(), endswith(), replace(), split(), sprintf(),
    substring()
    • 正規表現: re_match(), regex.split()
    • 型判定: is_number(), is_string(), is_set()
    • エンコーディング: json.marshal()/unmarshal(), yaml.marshal()/unmarshal()
    • そのほか Token Signing/Verification, 時間, HTTP通信 などなど
    18

    View Slide

  19. 集合演算
    • 集合を扱うことができる
    • 和集合、差集合、積集合などの
    計算が可能
    • 空集合は {} ではなく set()
    19
    resources = {
    "pod",
    "service",
    "deployment",
    "node"
    }
    apps = {
    "pod",
    "deployment"
    }
    hello[x] {
    # 差集合の計算
    x := resources - apps
    }

    View Slide

  20. コマンドラインツール
    • バイナリダウンロード
    • https://github.com/open-policy-agent/opa/releases
    • 文法チェック
    • opa check hoge.rego
    • 実行
    • opa eval --input input.json --data hoge.rego –format pretty "data.query"
    • フォーマット
    • opa fmt -w hoge.rego
    20

    View Slide

  21. テスト
    • with xxx as yyy 構文を利用して、
    テスト対象のルールに任意の入力
    を与えることができる。
    • 下記のコマンドでテスト実行
    • opa test -v .
    21
    package k8s.test_admission
    import data.k8s.admission
    test_deny {
    input1 := {
    "review": {
    "namespace": "kube-system"
    },
    "parameters": {
    "systemNamespaces": [
    "kube-system",
    "kube-public"
    ]
    }
    }
    # k8s.admission.violation というルールをテスト
    res := admission.violation with input as input1
    count(res) > 0
    }

    View Slide

  22. Gatekeeper
    • Open Policy Agent を Kubernetes
    で使えるようにしたもの
    • Kubernetes の Admission
    Controller Webhook による呼び
    出し
    • ポリシーを Custom Resource と
    して定義可能
    • 共通処理をライブラリとして利用
    可能
    22
    出展: vhttps://kubernetes.io/blog/2019/08/06/opa-
    gatekeeper-policy-and-governance-for-kubernetes/

    View Slide

  23. Admission Controller Webhook
    • Kubernetes の拡張機能のひとつ
    • Kubernetes のリソースを作成、更新、削除するタイミング
    で外部の Webhook API を呼び出す
    • Validating: リソースが条件を満たしているかチェック
    • Mutating: リソースの一部を書き換える
    • Gatekeeper v3 では未対応 (対応中)
    23

    View Slide

  24. Gatekeeper の歴史
    • Gatekeeper v1
    • OpenPolicyAgent + kube-mgmt
    • Gatekeeper v2
    • OpenPolicyAgent + kube-mgmt + kube-policy-controller
    • Gatekeeper v3
    • kubebuilder を利用して全面刷新
    24

    View Slide

  25. 動かしてみよう
    • https://github.com/zoetrope/gatekee
    per-demo
    • kind をセットアップ
    • kind create cluster --name gatekeeper
    --config cluster.yaml
    • kubectl apply -f https://raw.githubuse
    rcontent.com/open-policy-agent/gate
    keeper/master/deploy/gatekeeper.ya
    ml
    25
    # cluster.yaml
    kind: Cluster
    apiVersion: kind.sigs.k8s.io/v1alpha3
    kubeadmConfigPatches:
    - |
    apiVersion: kubeadm.k8s.io/v1beta2
    kind: ClusterConfiguration
    metadata:
    name: config
    apiServer:
    extraArgs:
    "enable-admission-plugins":
    "ValidatingAdmissionWebhook"
    nodes:
    - role: control-plane
    - role: worker

    View Slide

  26. 動かしてみよう
    • 特定のレジストリ以外のコンテナイメージの利用を禁止するポリ
    シーを用意する
    • ポリシーを記述した ConstraintTemplate カスタムリソースを作成
    • ポリシーの適用対象とパラメータを記述した Constraint カスタムリ
    ソースを作成
    26

    View Slide

  27. カスタムリソース
    • ConstraintTemplate
    • Gatekeeper が Custom Resource Definition を用意している
    • Constraint の名前とスキーマを定義
    • ポリシーを Rego で記述
    • Constraint
    • ConstraintTemplate から動的に作られる Custom Resource Definition
    • ポリシー適用対象リソースとパラメータを指定
    27

    View Slide

  28. ConstraintTemplate
    28
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
    name: k8sallowedrepos
    spec:
    crd:
    spec:
    names:
    kind: K8sAllowedRepos # Constraint の Custom Resource 名
    validation:
    # `parameters` フィールドのスキーマ
    openAPIV3Schema:
    properties:
    repos:
    type: array
    items:
    type: string
    targets: # 後述

    View Slide

  29. ConstraintTemplate
    29
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
    name: k8sallowedrepos
    spec:
    crd: # 省略
    targets:
    - target: admission.k8s.gatekeeper.sh # 固定
    rego: |
    package k8sallowedrepos
    violation[{"msg": msg}] {
    container := input.review.object.spec.containers[_]
    satisfied := [good | repo = input.parameters.repos[_];
    good = startswith(container.image, repo)]
    not any(satisfied)
    msg := sprintf("container <%v> has an invalid image repo <%v>",
    [container.name, container.image])
    }

    View Slide

  30. Constraint
    30
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sAllowedRepos
    metadata:
    name: repo-is-cybozu
    spec:
    match: # 対象リソースを指定
    kinds:
    - apiGroups: [""]
    kinds: ["Pod"]
    parameters: # パラメータの指定。rego から input.parameters としてアクセス可能
    repos:
    - "quay.io/cybozu/"

    View Slide

  31. 入力データ
    31
    {
    "review": { # AdmissionReview
    "uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
    "kind": {"group":"apps","version":"v1","kind":"Pod"},
    "resource": {"group":"apps","version":"v1","resource":"pods"},
    "operation": "CREATE",
    "userInfo": {
    "username": "admin",
    "groups": ["system:authenticated","system:masters"],
    },
    "object": {
    "apiVersion":"v1","kind":"Pod",...
    },
    },
    # Constraintで指定したパラメータ
    "parameters": {"repos": ["quay.io/cybozu",...]}
    }

    View Slide

  32. 検証してみよう
    $ kubectl apply -f nginx.yaml
    Error from server ([denied by repo-is-cybozu] container
    has an invalid image repo ): error
    when creating "nginx.yaml": admission webhook
    "validation.gatekeeper.sh" denied the request: [denied by
    repo-is-cybozu] container has an invalid image
    repo
    上記のようなメッセージが表示されたら成功
    32
    # nginx.yaml
    apiVersion: v1
    kind: Pod
    metadata:
    labels:
    run: nginx
    name: nginx
    namespace: default
    spec:
    containers:
    - name: nginx
    image: nginx:latest

    View Slide

  33. データの同期
    • Kubernetes クラスタの特定リ
    ソースを Rego から利用できるよ
    うにする。
    • client-go/informer により結果を
    キャッシュ。
    • Audit 機能や namespaceSelector
    を利用するときにも必要。
    33
    apiVersion: config.gatekeeper.sh/v1alpha1
    kind: Config
    metadata:
    name: config
    namespace: "gatekeeper-system"
    spec:
    sync:
    syncOnly:
    - group: ""
    version: "v1"
    kind: "Namespace"
    - group: ""
    version: "v1"
    kind: "Pod"

    View Slide

  34. 同期データの利用方法
    • Cluster-scoped Resource
    • data.inventory.cluster[rsion>][][]
    • Namespaced Resource
    • data.inventory.namespace[mespace>][][ind>][]
    34
    allPods[name] = pod {
    # 全namespaceのPodを取得
    pod := data.inventory
    .namespace[_][_]["Pod"][name]
    }

    View Slide

  35. Audit
    • ValidatingAdmissionWebhook はリソースの作成、更新、削除など
    のタイミングで実行される
    • Audit 機能を利用すると、定期的にポリシーのチェックが実施される
    • 検証対象のリソースは同期設定しておく必要ある
    • Constraint リソースの Status に検証結果が保存される
    35

    View Slide

  36. トレース
    • トレース機能を利用すると、検証に
    利用した入力データや検証結果がロ
    グに出力される
    • 大量にログが出力されるので、デ
    バッグ用途での利用を推奨
    • 正直トレースの読み方がわからない
    36
    apiVersion:
    config.gatekeeper.sh/v1alpha1
    kind: Config
    metadata:
    name: config
    namespace: "gatekeeper-system"
    spec:
    validation:
    traces:
    - user: "kubernetes-admin"
    kind:
    group: ""
    version: "v1"
    kind: "Pod"
    dump: "All"

    View Slide

  37. Rego のテスト
    • ConstraintTemplate の中に Rego が埋め込まれてるのでテストしにくい。
    • ConstraintTemplate のベースファイルに Rego を埋め込む Kustomize プラグイ
    ンをつくってみた。
    • https://github.com/zoetrope/ConstraintTemplateGenerator
    37

    View Slide

  38. おしまい(所感)
    • 最初はとっつきにくいかもしれないけど、慣れればそれなりに書き
    やすい。
    • デバッグしにくいので、トレース周りは改善してほしい。
    • argo-cd と相性悪いのをなんとかしたい。
    • パフォーマンスがよくないかも?
    • https://github.com/open-policy-agent/gatekeeper/issues/266
    38

    View Slide