共计 3770 个字符,预计需要花费 10 分钟才能阅读完成。
系列专栏申明:比拟流水,次要是写一些踩坑的点,和实际中与文档差距较大的中央的思考。这个专栏的典型特色可能是 次佳实际
,争取能在大量的最佳实际中生存。
Open Policy Agent 吸引我的点在于 Policy as Code
,所以看上去整个云原生概念吸引我的点就在于 X as Code
或者更精确的说是 X as Declarative DSL
。
TODO:会有 JWT
的局部,然而第一稿来不及写了,能够珍藏当前来看。
在 PBAC: Policy Base Authorization Control
中有三个外围的概念,PIP
、PDP
、PEP
。
OPA
是一个 PDP
,即 规定引擎
。审计方在这里用 自然语言的 DSL
形容权限管制规定,OPA
执行这些规定并返回 allow
或 deny
。晚期的权限规定是单向的,只能从需要被翻译成面向过程的代码,而很难从曾经实现的代码反推出理论被执行的规定,也很难对规定进行更新或迁徙。应用 DSL
是量变的要害,它使得需要和代码能够双向翻译了。
一、申请流向
这是下面概念图落地后的实例图,有两个比拟显著的简化点是:
- 本文实际上只是第一道网关,只做简略的准入管制,不做行、列粒度的数据权限管制。所以和
Envoy(PEP)
配套的OPA(PDP)
没有去申请额定的PIP
取得更多属性,而是仅应用Envoy
带来的属性包含JWT
。因而这里通常只会携带以后用户的id
和要害role
。如果要做细粒度的权限管制,应该在Service
处再加一套PEP + OPA(PDP)
。 OPA
要求所有的Policy
都在内存里。它提供了 restful api 用来更新内存中的 policy,这是大部分入门介绍的形式,但看上去没有实际意义。另外还提供了从数据源实时同步的形式,这个应该才是 正确的形式,不在本文中详细描述了。本文在启动时从文件中加载。
docker-compose.yml
app:
container_name: app
image: hub.docker.com/example/app:latest
networks:
- traefik
# 这里不须要配置 traefik 相干的 labels,因为理论对外裸露的是 envoy
app-envoy:
container_name: app-envoy
image: envoyproxy/envoy-alpine:v1.17.4
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`api.example.com`)"
# 省略其它必须的 traefik labels
volumes:
- "/path/to/envoy.yaml:/etc/envoy/envoy.yaml"
app-opa:
container_name: app-opa
image: openpolicyagent/opa:0.35.0-envoy-5-rootless
networks:
- traefik
volumes:
- "/path/to/policy.rego:/config/policy.rego"
command:
- run
- --log-level=debug
- --set=decision_logs.console=true
- --skip-version-check # 这里敞开向 open telemetry 上报埋点
- --server
- --set=plugins.envoy_ext_authz_grpc.addr=:9191
- --set=plugins.envoy_ext_authz_grpc.path=com/example/app/opa/allow
- /config/policy.rego
几个踩坑点:
opa
应用的是内置envoy plugin
的 版本
envoy.yaml
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 80
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
# 省略
route_config:
# 省略
http_filters:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: V3
grpc_service:
envoy_grpc:
cluster_name: app-opa
timeout: 0.5s
# 省略
- name: envoy.filters.http.cors
- name: envoy.filters.http.router
typed_config: {}
clusters:
- name: app
connect_timeout: 0.25s
type: strict_dns
dns_lookup_family: V4_ONLY
lb_policy: round_robin
load_assignment:
cluster_name: app
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: app
port_value: 8080
- name: app-opa
connect_timeout: 0.25s
type: strict_dns
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: {}
load_assignment:
cluster_name: app-opa
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: app-opa
port_value: 9191
几个踩坑点:
envoy 1.17
开始默认应用v3
,所以降级上来的不少配置语法要改,文档比拟难找,没有手把手教程,但理论改好当前平滑降级- 模仿在一个
Pod
内的场景,cluster
的定义用的是在 docker 内的 name,没有去 traefik 再兜一圈进来,所以也不须要为 app 配置 traefik labels 依据 host 做路由
policy.rego
package com.example.app.opa
import input.attributes.request.http as http_request
default allow = {
"allowed": false,
"headers": {"x-envoy-opa": "deny", "content-type": "application/json"},
"body": "{\"code\": -1, \"message\": \"deny\"}",
"http_status": 403
}
allow = response {
http_request.method == "OPTIONS"
response := {
"allowed": true,
"headers": {"x-envoy-opa": "allow"}
}
}
allow = response {allowed_methods := ["GET", "POST", "PUT", "DELETE"]
http_request.method == allowed_methods[_]
http_request.headers["Authorzation"] == "Basic BasicAccessToken"
glob.match("/app/open-api/*", [], http_request.path)
response := {
"allowed": true,
"headers": {"x-envoy-opa": "allow"}
}
}
几个踩坑点:
- 挺顺利的,
Rego
的语法值得详解一下,前面补充 - 应用的是 opa-envoy-plugin,所以有些语法不是 opa 自带的,而是 envoy-plugin 集成进来的,比方
glob.match
- 等有空钻研 opa 调实时接口更新规定,再补充一下
参考资料:
- Envoy Getting Started
- Getting Started With Rego,对于 Rego 的一些反直觉的语法,但你可能须要适应这些语法,在 DSL 里写代码的确是全新的体验
- Policy Language
- https://github.com/NewbMiao/o…
正文完