系列专栏申明:比拟流水,次要是写一些踩坑的点,和实际中与文档差距较大的中央的思考。这个专栏的典型特色可能是 次佳实际
,争取能在大量的最佳实际中生存。
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.opaimport input.attributes.request.http as http_requestdefault 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...