©2021 VMware, Inc.
Open Policy Agent (OPA) ⼊⾨
Motonori Shindo / motonori_shindo
VMware DevOps Meetup #7
2021/01/20
2
©2021 VMware, Inc.
1980年代の思い出
3
©2021 VMware, Inc.
What is Policy ?
何かしらによって課される制約に対して、どうある
べきかを規定するもの
• 法律、条例
• ビジネスルール
• アプリケーション要求
• 地域的制約
• セキュリティ的要件
• …
Photo by Scott Graham on Unsplash
4
©2021 VMware, Inc.
多くのシステムには個別にポリシーが存在している
Policy
Policy
Policy
Policy
Policy
Policy
Policy
Policy
5
©2021 VMware, Inc.
Open Policy Agent (OPA) とは
Domain Agnositc な Policy Engine
OPA は Policy Decision だけを⾏い、Policy
Enforcement には関与しない
Rego という Datalog Inspired な宣⾔的 Policy ⾔
語を持つ
オープンソース
利⽤⽅法
Library (Go)、REST API、Wasm
Source: https://www.openpolicyagent.org/docs/latest/
6
©2021 VMware, Inc.
Rego Primer by example
Network, Server, App Toplogies
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
JSON
web app db
p1 p2 p3 p4
Net1 (public)
Net2 (private)
https ssh tomcat mysql
Internet
7
©2021 VMware, Inc.
Rego Primer by example (1)
Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages
package example.rules
any_public_networks = true {
net := input.networks[_]
net.public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"any_public_networks": true
}
Policy Input
Output
8
©2021 VMware, Inc.
Rego Primer by example (1)
Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages
package example.rules
any_public_networks = true {
net := input.networks[_]
net.public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"any_public_networks": true
}
Policy Input
Output
Complete Rule:
<head> = <term> { <body> }
<body> が true であれば <head> = <term> になる。
”= true” は省略可能。
9
©2021 VMware, Inc.
Rego Primer by example (1)
Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages
package example.rules
any_public_networks = true {
net := input.networks[_]
net.public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"any_public_networks": true
}
Policy Input
Output
“input” は予約されたグローバル変数。
10
©2021 VMware, Inc.
Rego Primer by example (1)
Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages
package example.rules
any_public_networks = true {
net := input.networks[_]
net.public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"any_public_networks": true
}
Policy Input
Output
[ ] は配列を表す。‘_’ は無名変数。後に参
照する必要がなければ無名変数を使うこと
ができる。
11
©2021 VMware, Inc.
Rego Primer by example (1)
Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages
package example.rules
any_public_networks = true {
net := input.networks[_]
net.public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"any_public_networks": true
}
Policy Input
Output
<body> 中の複数⾏の <expression> は、Logical
AND として解釈される。”<express1> ;
<expression2>” と書いても同様。
12
©2021 VMware, Inc.
Rego Primer by example (1)
Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages
package example.rules
any_public_networks = true {
net := input.networks[_]
net.public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"any_public_networks": true
}
Policy Input
Output
”:=” は assginment(代⼊) operator。Rego の変数
は immutable なので、同じ変数に⼆度 ”:=” で代⼊す
ることはできない。
13
©2021 VMware, Inc.
Rego Primer by example (1)
Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages
package example.rules
any_public_networks = true {
net := input.networks[_]
net.public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"any_public_networks": true
}
Policy Input
Output
Package は Rego のルールに名前空間
を作り出す。Data API で呼び出される
場合も、この名前空間が使われる。
14
©2021 VMware, Inc.
Rego Primer by example (2)
Partial Rules
package example.rules
public_network[net.id] {
net := input.networks[_]
net.public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"public_network": [
"net1"
]
}
Policy Input
Output
<head> が [ ] を持っている場合は、Partial
Rule と呼ばれ、複数の値をセットするのに
使われる。
15
©2021 VMware, Inc.
Rego Primer by example (3)
Logical OR
package example.rules
shell_accessible[server.id] {
server := input.servers[_]
server.proto[_] == "telnet"
}
shell_accessible[server.id] {
server := input.servers[_]
server.proto[_] == "ssh"
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"shell_accessible": [
"web"
]
}
Policy Input
Output
同じ <head> を持つルールが複数ある場合
は、それらは Logical OR と解釈される。
16
©2021 VMware, Inc.
Rego Primer by example (4)
Iterations
package example.rules
public_ports[id] {
some i, j
id := input.ports[i].id
input.ports[i].network == input.networks[j].id
input.networks[j].public
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"public_ports": [
"p1"
]
}
Policy Input
Output
Rego では <expression> に “some” で宣⾔
した変数を埋め込むことで暗黙的にループ
が形成される
18
©2021 VMware, Inc.
クイズ
Public な network に接続されている port を持っている server のリストを取得
package example.rules
public_servers[server] {
some i, j, k
input.servers[i].ports[_] == input.ports[j].id
input.networks[k].id == input.ports[j].network
input.networks[k].public
server := input.servers[i].id
}
{
"servers": [
{ "id": "web",
"proto": ["https", "ssh"],
"ports": ["p1", "p2"]},
{ "id": "app",
"proto": ["tomcat"],
"ports": ["p3"]},
{ "id": "db",
"proto": ["mysql"],
"ports": ["p4"]}
],
"networks": [
{"id": "net1", "public": true},
{"id": "net2", "public": false}
],
"ports": [
{"id": "p1", "network": "net1"},
{"id": "p2", "network": "net2"},
{"id": "p3", "network": "net2"},
{"id": "p4", "network": "net2"}
]
}
{
"public_servers": [
"web"
]
}
Policy Input
Output
??? 回答は後⽇ Tweet します。
19
©2021 VMware, Inc.
Built-in Functions
https://www.openpolicyagent.org/docs/latest/policy-reference/#built-in-functions
Comparisons
• ==, !=, <, <=, >, >=
Numbers
• +, -, *, /, %, round(), abs(), etc.
Aggregates
• count(), sum(), max(), min(), product(), sort(), etc.
Arrays
• concat(), slice()
Set
• get(), remove(), union(), filter(), etc.
Strings
• concat(), contains(), startwith(), endswith(), etc.
Regex / Glob
• match(), is_valid(), split(), find_n(), etc.
Glob
• match(), quote_meta()
Bitwise
• or(), and(), negate(), xor(), lsh(), rsh()
Conversions
• to_number()
Types
• is_number(), is_string(), is_boolean(), etc.
Encoding
• encode(), decode(), marshal(), unmarshal(), etc.
20
©2021 VMware, Inc.
Built-in Functions (cont’d)
https://www.openpolicyagent.org/docs/latest/policy-reference/#built-in-functions
Token Signing
• encode_sign_raw(), encode_sign()
Token Verification
• verify_rs256(), verify_rs384(), etc.
Time
• date(), clock(), weekday(), add_date(), etc.
Cryptography
• md5(), sha1(), sha256(), parse_certficates(), etc.
Graphs
• walk(), reachable()
HTTP
• send()
Net
• cidr_contain(), cidr_intersects(), etc.
UUID
• rfc4122()
Semantic Versions
• is_valid(), compare()
Rego
• parse_module()
OPA
• runtime()
Debug
• trace()
21
©2021 VMware, Inc.
Rego Playground
https://play.openpolicyagent.org/
22
©2021 VMware, Inc.
OPA Ecosystem
23
©2021 VMware, Inc.
Kubernetes Integration - Gatekeeper
Kubernetes API
Server と OPA の
間のブリッジとして
動作
API Server が
Gatekeeper の
Webhook をトリ
ガー
課したい制約を
Rego で記述
Source: https://kubernetes.io/blog/2019/08/06/opa-gatekeeper-policy-and-governance-for-kubernetes/
24
©2021 VMware, Inc.
Policy Template and Policy Instance CRD
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
# Schema for the `parameters` field
openAPIV3Schema:
properties:
labels:
type: array
items: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("you must provide labels: %v", [missing])
}
apiVersion:
constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-gk
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["gatekeeper"]
25
©2021 VMware, Inc.
Gatekeeper Policy Library
https://github.com/open-policy-agent/gatekeeper-library/tree/master/library
General
• allowedrepos
• block-noodepoort-services
• containerlimits
• containerresouorceratios
• externalip
• httpsonly
• imagedigests
• requiredlabel
• uniqingresshost
• uniqueserviceselector
Pod Security Policy
• allow-privilege-escalatiion
• apparmor
• capability
• flexvolume-drivers
• forbidden-sysctls
• fsgroup
• host-filesystem
• host-namespace
• host-network-ports
• privileged-containers
• proc-mount
• read-only-root-filesystem
• seccomp
• selinux
• users
• volumes
27
©2021 VMware, Inc.
Tanzu Mission Control -- Policies / Templates
Policy Template の⼀覧
28
©2021 VMware, Inc.
Tanzu Mission Control -- Policies / Templates
Policy Template の表⽰
29
©2021 VMware, Inc.
Tanzu Mission Control -- Policies / Templates
Policy Template の作成
30
©2021 VMware, Inc.
Tanzu Mission Control -- Policy Assignments
31
©2021 VMware, Inc.
Tanzu Mission Control -- Policy Assignments
Custom Policy Assignment 作成
32
©2021 VMware, Inc.
Tanzu Mission Control -- Policy Assignments
Custom Policy Assignment 作成
33
©2021 VMware, Inc.
Tanzu Mission Control -- Policy Insights
Violation の表⽰
34
©2021 VMware, Inc.
Tanzu Mission Control -- Policy Insights
Violation の詳細表⽰
35
©2021 VMware, Inc.
Tanzu Mission Control Demo
Policies
36
©2021 VMware, Inc.
問題点
• ClusterIP と spec.externalIPs フィールドを触
れる⼈は、⾃由にトラフィックをステアリング
できる
回避⽅法
• OPA で Service の spec.exterrnalIPs と
spec.loadBalancerIP を許可した IP アドレス
のみ許可するポリシーを適⽤する
CVE-2021-8554 を TMC/OPA で回避する
https://tanzu.vmware.com/content/blog/tutorial-vmware-tanzu-mission-control-
kubernetes-vulnerability-cve-2021-8554
40
©2021 VMware, Inc.
Open Policy Agent 本家のサイト
• https://www.openpolicyagent.org/
• https://github.com/open-policy-agent
Tanzu Mission Control で学ぶ Open Policy Agent Part 1 〜 4 by 星野さん
• https://blog.lespaulstudioplus.info/posts/tmc-demanabu-opa/
OPA Deep Dive, Kubecon NA 2019
• https://www.youtube.com/watch?v=Uj2N9S58GLU
TGIK 119 Gatekeeper and OPA
• https://www.youtube.com/watch?v=ZJgaGJm9NJE
Styra
• https://www.styra.com/
• https://academy.styra.com/
References
©2021 VMware, Inc.
Thank You

Open Policy Agent (OPA) 入門

  • 1.
    ©2021 VMware, Inc. OpenPolicy Agent (OPA) ⼊⾨ Motonori Shindo / motonori_shindo VMware DevOps Meetup #7 2021/01/20
  • 2.
  • 3.
    3 ©2021 VMware, Inc. Whatis Policy ? 何かしらによって課される制約に対して、どうある べきかを規定するもの • 法律、条例 • ビジネスルール • アプリケーション要求 • 地域的制約 • セキュリティ的要件 • … Photo by Scott Graham on Unsplash
  • 4.
  • 5.
    5 ©2021 VMware, Inc. OpenPolicy Agent (OPA) とは Domain Agnositc な Policy Engine OPA は Policy Decision だけを⾏い、Policy Enforcement には関与しない Rego という Datalog Inspired な宣⾔的 Policy ⾔ 語を持つ オープンソース 利⽤⽅法 Library (Go)、REST API、Wasm Source: https://www.openpolicyagent.org/docs/latest/
  • 6.
    6 ©2021 VMware, Inc. RegoPrimer by example Network, Server, App Toplogies { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } JSON web app db p1 p2 p3 p4 Net1 (public) Net2 (private) https ssh tomcat mysql Internet
  • 7.
    7 ©2021 VMware, Inc. RegoPrimer by example (1) Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages package example.rules any_public_networks = true { net := input.networks[_] net.public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "any_public_networks": true } Policy Input Output
  • 8.
    8 ©2021 VMware, Inc. RegoPrimer by example (1) Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages package example.rules any_public_networks = true { net := input.networks[_] net.public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "any_public_networks": true } Policy Input Output Complete Rule: <head> = <term> { <body> } <body> が true であれば <head> = <term> になる。 ”= true” は省略可能。
  • 9.
    9 ©2021 VMware, Inc. RegoPrimer by example (1) Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages package example.rules any_public_networks = true { net := input.networks[_] net.public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "any_public_networks": true } Policy Input Output “input” は予約されたグローバル変数。
  • 10.
    10 ©2021 VMware, Inc. RegoPrimer by example (1) Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages package example.rules any_public_networks = true { net := input.networks[_] net.public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "any_public_networks": true } Policy Input Output [ ] は配列を表す。‘_’ は無名変数。後に参 照する必要がなければ無名変数を使うこと ができる。
  • 11.
    11 ©2021 VMware, Inc. RegoPrimer by example (1) Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages package example.rules any_public_networks = true { net := input.networks[_] net.public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "any_public_networks": true } Policy Input Output <body> 中の複数⾏の <expression> は、Logical AND として解釈される。”<express1> ; <expression2>” と書いても同様。
  • 12.
    12 ©2021 VMware, Inc. RegoPrimer by example (1) Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages package example.rules any_public_networks = true { net := input.networks[_] net.public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "any_public_networks": true } Policy Input Output ”:=” は assginment(代⼊) operator。Rego の変数 は immutable なので、同じ変数に⼆度 ”:=” で代⼊す ることはできない。
  • 13.
    13 ©2021 VMware, Inc. RegoPrimer by example (1) Complete Rules, Arrays, Logical AND, Assignments, Anonymous Variable, Packages package example.rules any_public_networks = true { net := input.networks[_] net.public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "any_public_networks": true } Policy Input Output Package は Rego のルールに名前空間 を作り出す。Data API で呼び出される 場合も、この名前空間が使われる。
  • 14.
    14 ©2021 VMware, Inc. RegoPrimer by example (2) Partial Rules package example.rules public_network[net.id] { net := input.networks[_] net.public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "public_network": [ "net1" ] } Policy Input Output <head> が [ ] を持っている場合は、Partial Rule と呼ばれ、複数の値をセットするのに 使われる。
  • 15.
    15 ©2021 VMware, Inc. RegoPrimer by example (3) Logical OR package example.rules shell_accessible[server.id] { server := input.servers[_] server.proto[_] == "telnet" } shell_accessible[server.id] { server := input.servers[_] server.proto[_] == "ssh" } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "shell_accessible": [ "web" ] } Policy Input Output 同じ <head> を持つルールが複数ある場合 は、それらは Logical OR と解釈される。
  • 16.
    16 ©2021 VMware, Inc. RegoPrimer by example (4) Iterations package example.rules public_ports[id] { some i, j id := input.ports[i].id input.ports[i].network == input.networks[j].id input.networks[j].public } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "public_ports": [ "p1" ] } Policy Input Output Rego では <expression> に “some” で宣⾔ した変数を埋め込むことで暗黙的にループ が形成される
  • 17.
    18 ©2021 VMware, Inc. クイズ Publicな network に接続されている port を持っている server のリストを取得 package example.rules public_servers[server] { some i, j, k input.servers[i].ports[_] == input.ports[j].id input.networks[k].id == input.ports[j].network input.networks[k].public server := input.servers[i].id } { "servers": [ { "id": "web", "proto": ["https", "ssh"], "ports": ["p1", "p2"]}, { "id": "app", "proto": ["tomcat"], "ports": ["p3"]}, { "id": "db", "proto": ["mysql"], "ports": ["p4"]} ], "networks": [ {"id": "net1", "public": true}, {"id": "net2", "public": false} ], "ports": [ {"id": "p1", "network": "net1"}, {"id": "p2", "network": "net2"}, {"id": "p3", "network": "net2"}, {"id": "p4", "network": "net2"} ] } { "public_servers": [ "web" ] } Policy Input Output ??? 回答は後⽇ Tweet します。
  • 18.
    19 ©2021 VMware, Inc. Built-inFunctions https://www.openpolicyagent.org/docs/latest/policy-reference/#built-in-functions Comparisons • ==, !=, <, <=, >, >= Numbers • +, -, *, /, %, round(), abs(), etc. Aggregates • count(), sum(), max(), min(), product(), sort(), etc. Arrays • concat(), slice() Set • get(), remove(), union(), filter(), etc. Strings • concat(), contains(), startwith(), endswith(), etc. Regex / Glob • match(), is_valid(), split(), find_n(), etc. Glob • match(), quote_meta() Bitwise • or(), and(), negate(), xor(), lsh(), rsh() Conversions • to_number() Types • is_number(), is_string(), is_boolean(), etc. Encoding • encode(), decode(), marshal(), unmarshal(), etc.
  • 19.
    20 ©2021 VMware, Inc. Built-inFunctions (cont’d) https://www.openpolicyagent.org/docs/latest/policy-reference/#built-in-functions Token Signing • encode_sign_raw(), encode_sign() Token Verification • verify_rs256(), verify_rs384(), etc. Time • date(), clock(), weekday(), add_date(), etc. Cryptography • md5(), sha1(), sha256(), parse_certficates(), etc. Graphs • walk(), reachable() HTTP • send() Net • cidr_contain(), cidr_intersects(), etc. UUID • rfc4122() Semantic Versions • is_valid(), compare() Rego • parse_module() OPA • runtime() Debug • trace()
  • 20.
    21 ©2021 VMware, Inc. RegoPlayground https://play.openpolicyagent.org/
  • 21.
  • 22.
    23 ©2021 VMware, Inc. KubernetesIntegration - Gatekeeper Kubernetes API Server と OPA の 間のブリッジとして 動作 API Server が Gatekeeper の Webhook をトリ ガー 課したい制約を Rego で記述 Source: https://kubernetes.io/blog/2019/08/06/opa-gatekeeper-policy-and-governance-for-kubernetes/
  • 23.
    24 ©2021 VMware, Inc. PolicyTemplate and Policy Instance CRD apiVersion: templates.gatekeeper.sh/v1beta1 kind: ConstraintTemplate metadata: name: k8srequiredlabels spec: crd: spec: names: kind: K8sRequiredLabels validation: # Schema for the `parameters` field openAPIV3Schema: properties: labels: type: array items: string targets: - target: admission.k8s.gatekeeper.sh rego: | package k8srequiredlabels violation[{"msg": msg, "details": {"missing_labels": missing}}] { provided := {label | input.review.object.metadata.labels[label]} required := {label | label := input.parameters.labels[_]} missing := required - provided count(missing) > 0 msg := sprintf("you must provide labels: %v", [missing]) } apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sRequiredLabels metadata: name: ns-must-have-gk spec: match: kinds: - apiGroups: [""] kinds: ["Namespace"] parameters: labels: ["gatekeeper"]
  • 24.
    25 ©2021 VMware, Inc. GatekeeperPolicy Library https://github.com/open-policy-agent/gatekeeper-library/tree/master/library General • allowedrepos • block-noodepoort-services • containerlimits • containerresouorceratios • externalip • httpsonly • imagedigests • requiredlabel • uniqingresshost • uniqueserviceselector Pod Security Policy • allow-privilege-escalatiion • apparmor • capability • flexvolume-drivers • forbidden-sysctls • fsgroup • host-filesystem • host-namespace • host-network-ports • privileged-containers • proc-mount • read-only-root-filesystem • seccomp • selinux • users • volumes
  • 25.
    27 ©2021 VMware, Inc. TanzuMission Control -- Policies / Templates Policy Template の⼀覧
  • 26.
    28 ©2021 VMware, Inc. TanzuMission Control -- Policies / Templates Policy Template の表⽰
  • 27.
    29 ©2021 VMware, Inc. TanzuMission Control -- Policies / Templates Policy Template の作成
  • 28.
    30 ©2021 VMware, Inc. TanzuMission Control -- Policy Assignments
  • 29.
    31 ©2021 VMware, Inc. TanzuMission Control -- Policy Assignments Custom Policy Assignment 作成
  • 30.
    32 ©2021 VMware, Inc. TanzuMission Control -- Policy Assignments Custom Policy Assignment 作成
  • 31.
    33 ©2021 VMware, Inc. TanzuMission Control -- Policy Insights Violation の表⽰
  • 32.
    34 ©2021 VMware, Inc. TanzuMission Control -- Policy Insights Violation の詳細表⽰
  • 33.
    35 ©2021 VMware, Inc. TanzuMission Control Demo Policies
  • 34.
    36 ©2021 VMware, Inc. 問題点 •ClusterIP と spec.externalIPs フィールドを触 れる⼈は、⾃由にトラフィックをステアリング できる 回避⽅法 • OPA で Service の spec.exterrnalIPs と spec.loadBalancerIP を許可した IP アドレス のみ許可するポリシーを適⽤する CVE-2021-8554 を TMC/OPA で回避する https://tanzu.vmware.com/content/blog/tutorial-vmware-tanzu-mission-control- kubernetes-vulnerability-cve-2021-8554
  • 35.
    40 ©2021 VMware, Inc. OpenPolicy Agent 本家のサイト • https://www.openpolicyagent.org/ • https://github.com/open-policy-agent Tanzu Mission Control で学ぶ Open Policy Agent Part 1 〜 4 by 星野さん • https://blog.lespaulstudioplus.info/posts/tmc-demanabu-opa/ OPA Deep Dive, Kubecon NA 2019 • https://www.youtube.com/watch?v=Uj2N9S58GLU TGIK 119 Gatekeeper and OPA • https://www.youtube.com/watch?v=ZJgaGJm9NJE Styra • https://www.styra.com/ • https://academy.styra.com/ References
  • 36.