Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up
for free
Open Policy Agent / Gatekeeper 勉強会
Akihiro Ikezoe
August 26, 2019
Technology
4
450
Open Policy Agent / Gatekeeper 勉強会
Akihiro Ikezoe
August 26, 2019
Tweet
Share
More Decks by Akihiro Ikezoe
See All by Akihiro Ikezoe
zoetrope
7
5.2k
zoetrope
7
3.1k
zoetrope
3
12k
zoetrope
4
2.3k
zoetrope
10
1.5k
Other Decks in Technology
See All in Technology
tzkoba
0
390
asaju7142501
0
250
clustervr
0
200
greymd
0
600
am7cinnamon
2
2.7k
line_developers
PRO
3
480
clustervr
0
180
kenya888
1
120
soachr
1
150
caori_t
0
150
zaki134rp
1
180
y0hgi
1
370
Featured
See All Featured
iamctodd
17
1.8k
addyosmani
1348
190k
akmur
252
19k
philhawksworth
190
17k
mza
80
4.1k
dougneiner
55
5.4k
sugarenia
233
830k
bkeepers
52
4.1k
kastner
54
1.9k
jakevdp
774
200k
matthewcrist
73
7.5k
paulrobertlloyd
71
1.4k
Transcript
Open Policy Agent Gatekeeper 勉強会 2019/08/26 (2019/11/24改訂) 池添 明宏
目次 • OpenPolicyAgent とは • Document • Rego • Gatekeeper
とは • ポリシーの作り方 • 機能紹介 2
Open Policy Agent とは • 軽量な汎用ポリシーエンジン • ポリシーに基づいて入力データの検証をおこなう • 特徴
• 宣言的な記述でポリシーの読み書きがしやすい • コンパイルし直すことなくポリシーの変更が可能 3
何に使えるの? • 例えば Kubernetes において、RBAC よりも柔軟なルールを適用でき る。 • 例: •
Pod に resource フィールドの指定を強制する • 利用可能なコンテナレジストリを制限する • 特定のユーザーに一部のリソースへのアクセスを制限する 4
Data & Policy 5 • Data (Document) • サービスやユーザーが用意するデータ •
JSON 形式 • Policy (Rule) • データに適用する検証ルール • Rego という独自言語で定義 出展: https://www.openpolicyagent.org/docs/latest/how-does-opa-work/
Document の種別 • Base Documents • サービスやユーザーが用意した データ • Virtual
Documents • Rule を適用した結果データ • Virtual Documents にさらに Rule を適用することも可能 6 出展: https://www.openpolicyagent.org/docs/latest/how-does-opa-work/
Documents の構造 • data • 検証に利用する静的なデータ • Rule を適用した結果データ •
input • 検証対象の入力データ 7 出展: https://www.openpolicyagent.org/docs/latest/how-does-opa-work/
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] }
Rules • Rego という独自言語でデータの検証ルールを記述する • Rego • Datalog という Prolog
系言語をインスパイア • 宣言的な記述が可能 • The Rego Playground で試してみよう • https://play.openpolicyagent.org/ 9
Rego による Rule の定義 10 # BODYの条件を満たした場合 # HEADの値を返す rule_name
<HEAD> { <BODY> } # 条件を満たさなかった場合 # undefinedを返す # 配列の場合は空配列を返す # HEADの省略は =trueと同じ rule1 { input.x < input.limit } # 固定値を返す rule2 = "abc" { input.x < input.limit } # 変数を返すことも可能 rule3 = x { x := input.x x < input.limit }
AND 条件と OR 条件 11 # 羅列するとAND条件 rule_name <HEAD> {
<CONDITION1> <CONDITION2> <CONDITION3> } # OR条件は同一名のルールを # 複数個用意する rule_name <HEAD1> { <CONDITION1> } rule_name <HEAD2> { <CONDITION2> }
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 }
else • 同一名の複数ルールは適用順序が考 慮されない。矛盾したルールは記述 することができない。 • 順序を考慮する場合は else キーワー ドを利用する。
13 rule_name <HEAD1> { <CONDITION1> } else <HEAD2> { <CONDITION2> }
繰り返し 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 }
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 }
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 }
関数定義 • ルールと似たような記法で関数 を定義することができる。 • 関数は引数を受け取ることがで きる。 • ルールのように Virtual
Document は生成されない 17 starts_with_foo(s) { startswith(s, "foo") } remove_prefix_foo(s) = r { starts_with_foo(s) r := substring(s, 3, -1) }
組み込み関数 • 集計: 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
集合演算 • 集合を扱うことができる • 和集合、差集合、積集合などの 計算が可能 • 空集合は {} ではなく
set() 19 resources = { "pod", "service", "deployment", "node" } apps = { "pod", "deployment" } hello[x] { # 差集合の計算 x := resources - apps }
コマンドラインツール • バイナリダウンロード • 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
テスト • 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 }
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/
Admission Controller Webhook • Kubernetes の拡張機能のひとつ • Kubernetes のリソースを作成、更新、削除するタイミング で外部の
Webhook API を呼び出す • Validating: リソースが条件を満たしているかチェック • Mutating: リソースの一部を書き換える • Gatekeeper v3 では未対応 (対応中) 23
Gatekeeper の歴史 • Gatekeeper v1 • OpenPolicyAgent + kube-mgmt •
Gatekeeper v2 • OpenPolicyAgent + kube-mgmt + kube-policy-controller • Gatekeeper v3 • kubebuilder を利用して全面刷新 24
動かしてみよう • 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
動かしてみよう • 特定のレジストリ以外のコンテナイメージの利用を禁止するポリ シーを用意する • ポリシーを記述した ConstraintTemplate カスタムリソースを作成 • ポリシーの適用対象とパラメータを記述した
Constraint カスタムリ ソースを作成 26
カスタムリソース • ConstraintTemplate • Gatekeeper が Custom Resource Definition を用意している
• Constraint の名前とスキーマを定義 • ポリシーを Rego で記述 • Constraint • ConstraintTemplate から動的に作られる Custom Resource Definition • ポリシー適用対象リソースとパラメータを指定 27
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: # 後述
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]) }
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/"
入力データ 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",...]} }
検証してみよう $ kubectl apply -f nginx.yaml Error from server ([denied
by repo-is-cybozu] container <nginx> has an invalid image repo <nginx:latest>): error when creating "nginx.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [denied by repo-is-cybozu] container <nginx> has an invalid image repo <nginx:latest> 上記のようなメッセージが表示されたら成功 32 # nginx.yaml apiVersion: v1 kind: Pod metadata: labels: run: nginx name: nginx namespace: default spec: containers: - name: nginx image: nginx:latest
データの同期 • 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"
同期データの利用方法 • Cluster-scoped Resource • data.inventory.cluster[<groupVe rsion>][<kind>][<name>] • Namespaced Resource
• data.inventory.namespace[<na mespace>][<groupVersion>][<k ind>][<name>] 34 allPods[name] = pod { # 全namespaceのPodを取得 pod := data.inventory .namespace[_][_]["Pod"][name] }
Audit • ValidatingAdmissionWebhook はリソースの作成、更新、削除など のタイミングで実行される • Audit 機能を利用すると、定期的にポリシーのチェックが実施される • 検証対象のリソースは同期設定しておく必要ある
• Constraint リソースの Status に検証結果が保存される 35
トレース • トレース機能を利用すると、検証に 利用した入力データや検証結果がロ グに出力される • 大量にログが出力されるので、デ バッグ用途での利用を推奨 • 正直トレースの読み方がわからない
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"
Rego のテスト • ConstraintTemplate の中に Rego が埋め込まれてるのでテストしにくい。 • ConstraintTemplate のベースファイルに
Rego を埋め込む Kustomize プラグイ ンをつくってみた。 • https://github.com/zoetrope/ConstraintTemplateGenerator 37
おしまい(所感) • 最初はとっつきにくいかもしれないけど、慣れればそれなりに書き やすい。 • デバッグしにくいので、トレース周りは改善してほしい。 • argo-cd と相性悪いのをなんとかしたい。 •
パフォーマンスがよくないかも? • https://github.com/open-policy-agent/gatekeeper/issues/266 38