第十五章:OPA — 通用策略引擎

“策略应该与代码分离,就像数据应该与逻辑分离一样。”

        mindmap
  root((OPA))
    核心概念
      Policy
      Data
      Query
      Decision
    Rego 语言
      规则
      函数
      集合操作
      测试
    部署模式
      Sidecar
      独立服务
      库模式
      WASM
    应用场景
      K8s Admission
      API Gateway
      微服务授权
      Terraform
    

15.1 OPA 是什么

OPA(Open Policy Agent)是 CNCF 毕业项目,提供通用的策略引擎。它将策略决策从应用代码中解耦出来。

OPA 工作流程:
┌──────────┐    ┌──────────────────┐    ┌──────────┐
│  应用     │───▶│      OPA         │◀───│  策略     │
│          │    │                  │    │ (Rego)   │
│ "Alice能 │    │  ┌────────────┐  │    │          │
│  删除X吗?"│    │  │ 策略评估    │  │    │ allow if │
│          │    │  │ 引擎       │  │    │ ...      │
│          │◀───│  └────────────┘  │    │          │
│ 允许/拒绝 │    │        ▲         │    └──────────┘
└──────────┘    │        │         │
                │  ┌─────┴──────┐  │
                │  │   数据      │  │
                │  │ (JSON)     │  │
                │  └────────────┘  │
                └──────────────────┘

15.2 Rego 语言

Rego 是 OPA 的策略语言,声明式风格:

基本规则

package authz

import rego.v1

# 默认拒绝
default allow := false

# 管理员允许所有操作
allow if {
    input.user.role == "admin"
}

# 用户可以读取自己的数据
allow if {
    input.action == "read"
    input.resource.owner == input.user.id
}

# 编辑者可以编辑非机密文档
allow if {
    input.action == "edit"
    input.user.role == "editor"
    input.resource.classification != "confidential"
}

输入和查询

// 输入(input)
{
  "user": {
    "id": "alice",
    "role": "editor",
    "department": "engineering"
  },
  "action": "edit",
  "resource": {
    "type": "document",
    "id": "doc-123",
    "owner": "bob",
    "classification": "internal"
  }
}

// 查询:data.authz.allow → true

高级特性

package authz

import rego.v1

# 集合推导:获取用户的所有权限
user_permissions contains perm if {
    some role in input.user.roles
    some perm in data.role_permissions[role]
}

# 函数
is_owner(resource) if {
    resource.owner == input.user.id
}

# 条件组合
allow if {
    input.action == "delete"
    is_owner(input.resource)
    input.resource.status != "archived"
}

# 基于时间的策略
allow if {
    input.action == "access"
    time.weekday(time.now_ns()) in ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
    hour := time.clock(time.now_ns())[0]
    hour >= 9
    hour < 18
}

Rego 测试

package authz_test

import rego.v1
import data.authz

test_admin_allowed if {
    authz.allow with input as {
        "user": {"role": "admin"},
        "action": "delete",
        "resource": {"id": "doc-1"}
    }
}

test_viewer_cannot_delete if {
    not authz.allow with input as {
        "user": {"role": "viewer"},
        "action": "delete",
        "resource": {"id": "doc-1"}
    }
}

test_owner_can_read if {
    authz.allow with input as {
        "user": {"id": "alice", "role": "viewer"},
        "action": "read",
        "resource": {"owner": "alice"}
    }
}
# 运行测试
opa test . -v

15.3 OPA 部署模式

模式

描述

延迟

适用场景

Sidecar

与应用同 Pod

极低(本地)

Kubernetes 微服务

独立服务

独立部署的 OPA 服务

低(网络)

集中策略管理

库模式

嵌入应用进程

极低

Go 应用

WASM

编译为 WebAssembly

极低

边缘计算、浏览器

Sidecar 模式:
┌─────────────────────────────────┐
│           Kubernetes Pod         │
│  ┌──────────┐  ┌──────────────┐ │
│  │  应用     │  │  OPA Sidecar │ │
│  │ 容器      │──▶│  容器        │ │
│  │          │  │  localhost   │ │
│  └──────────┘  └──────────────┘ │
└─────────────────────────────────┘

15.4 应用场景

Kubernetes Admission Control(Gatekeeper)

# 禁止使用 latest 标签的镜像
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDisallowedTags
metadata:
  name: no-latest-tag
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
  parameters:
    tags: ["latest"]

API Gateway 授权

package gateway

import rego.v1

default allow := false

# 公开端点无需认证
allow if {
    input.path in ["/health", "/metrics", "/docs"]
}

# 已认证用户可以访问 API
allow if {
    input.token.valid
    input.method == "GET"
    startswith(input.path, "/api/v1/")
}

# 管理员可以访问管理端点
allow if {
    input.token.valid
    "admin" in input.token.roles
    startswith(input.path, "/admin/")
}

# 速率限制
rate_limit := limit if {
    "premium" in input.token.roles
    limit := 1000
} else := limit if {
    limit := 100
}

Terraform 策略检查(Conftest)

package terraform

import rego.v1

# 禁止公开的 S3 存储桶
deny contains msg if {
    some resource in input.resource_changes
    resource.type == "aws_s3_bucket"
    resource.change.after.acl == "public-read"
    msg := sprintf("S3 bucket %s must not be public", [resource.address])
}

# 要求所有资源有标签
deny contains msg if {
    some resource in input.resource_changes
    not resource.change.after.tags.Environment
    msg := sprintf("Resource %s must have Environment tag", [resource.address])
}

15.5 Python 集成

import httpx
from fastapi import FastAPI, Depends, HTTPException, Request

app = FastAPI()
OPA_URL = "http://localhost:8181/v1/data/authz/allow"

async def check_opa_policy(request: Request, user: dict) -> bool:
    """调用 OPA 检查授权"""
    opa_input = {
        "input": {
            "user": user,
            "action": request.method.lower(),
            "path": request.url.path,
            "resource": {
                "type": request.url.path.split("/")[2] if len(request.url.path.split("/")) > 2 else None,
            }
        }
    }
    
    async with httpx.AsyncClient() as client:
        response = await client.post(OPA_URL, json=opa_input)
        result = response.json()
        return result.get("result", False)

async def authorize(request: Request, user: dict = Depends(get_current_user)):
    """授权中间件"""
    allowed = await check_opa_policy(request, user)
    if not allowed:
        raise HTTPException(status_code=403, detail="Access denied by policy")
    return user

@app.delete("/api/documents/{doc_id}")
async def delete_document(doc_id: str, user: dict = Depends(authorize)):
    return {"message": f"Document {doc_id} deleted by {user['id']}"}

15.6 OPA vs OpenFGA

维度

OPA

OpenFGA

模型

ABAC(策略驱动)

ReBAC(关系驱动)

语言

Rego

DSL

擅长

复杂条件逻辑

资源级权限继承

数据

策略 + JSON 数据

关系元组图

查询

“允许吗?”

“允许吗?” + “列出所有”

适用

K8s、API 策略、合规

文档协作、SaaS 权限

组合

✅ 可以组合使用

✅ 可以组合使用

最佳实践:用 OpenFGA 管理”谁与什么资源有什么关系”,用 OPA 管理”在什么条件下允许什么操作”。

15.7 小结

  • OPA 是 CNCF 毕业的通用策略引擎,将策略从代码中解耦

  • Rego 是声明式策略语言,支持复杂的条件逻辑

  • OPA 支持多种部署模式:Sidecar、独立服务、库、WASM

  • 广泛应用于 Kubernetes AdmissionAPI 授权IaC 合规

  • OPA 和 OpenFGA 互补:OPA 擅长策略逻辑,OpenFGA 擅长关系管理