首页
/ LiteLLM Terraform Provider:用 litellm_guardrails 数据源盘点网关上的全部护栏定义

LiteLLM Terraform Provider:用 litellm_guardrails 数据源盘点网关上的全部护栏定义

2026-09-07 17:43:56作者:伍霜盼Ellen

本篇围绕 LiteLLM 官方 Terraform Provider 的 litellm_guardrails 数据源文档展开:它不接收任何参数,一次性从 LiteLLM 代理(同时覆盖配置文件与数据库中登记的护栏)拉取全部护栏列表,且刻意不暴露可能携带 API Key 的敏感参数。读完后,你可以在 Terraform 配置中安全地输出护栏 ID、名称与定义位置,并理解该数据源在 Provider 侧(Go 源码)与代理侧(Python 端点)的完整实现链路。

数据源定位:只读、无参、聚合双来源

官方文档 guardrails.md 对该数据源的定义非常明确:

  • 功能:检索 LiteLLM 代理上配置的全部护栏(guardrails),来源同时包括 config(代理配置文件)与 DB(通过 API/控制台注册到数据库的护栏);
  • 安全边界:敏感的 litellm_params 不会被暴露——因为护栏的 litellm_params 中可能存放第三方服务的 API Key(如 Lakera、Presidio 等护栏后端凭证),IaC 状态文件中不应出现这些值;
  • 参数data "litellm_guardrails" 资源不接收任何参数,直接执行即可拉取全量列表;
  • 典型场景:跨环境(dev/staging/prod)比对护栏清单、在 Terraform 中做护栏存在性校验、将护栏 ID 作为输入传递给下游资源。

Provider 侧通过 provider.go 将其注册为 litellm_guardrails(复数,列表查询),与单条查询数据源 litellm_guardrail(按 guardrail_id 读取)并列,两者共用同一套读取逻辑。

快速上手:完整可用示例

以下是官方文档给出的示例用法,补上 Provider 声明后即为可直接运行的配置(Provider 声明方式参考 terraform/provider/README.md):

terraform {
  required_providers {
    litellm = {
      source  = "BerriAI/litellm"
      version = "~> 1.99.0" # 与你代理运行的 LiteLLM 版本保持一致
    }
  }
}

provider "litellm" {
  api_base = var.litellm_api_base
  api_key  = var.litellm_api_key
}

# 拉取全部护栏(config + DB)
data "litellm_guardrails" "all" {}

# 输出所有护栏 ID
output "guardrail_ids" {
  value = data.litellm_guardrails.all.ids
}

# 输出所有护栏名称
output "guardrail_names" {
  value = [for g in data.litellm_guardrails.all.guardrails : g.guardrail_name]
}

两个输出分别利用了数据源的两个顶层属性:ids 是扁平的 ID 列表,guardrails 是结构化对象列表,可用 Terraform 的 for 表达式进一步派生(如按 guardrail_definition_location 过滤出配置文件中定义的护栏)。

版本约束提示:README 明确说明 Provider 版本号与 LiteLLM 代理版本号一致(例如代理跑 1.99.0 就 pin ~> 1.99.0),并且 CI 会用 tools/endpointaudit/ 静态审计 Provider 调用的每个端点是否与代理生成的 OpenAPI schema 一致,因此保持两者同版本可以避免接口漂移。

参数与属性参考

Argument Reference

数据源不接受任何参数(no arguments)。调用 data "litellm_guardrails" "all" {} 即完成声明。

Attribute Reference

属性 类型 说明
guardrails List of object 护栏列表,每个元素包含下表 6 个字段
guardrails[].guardrail_id String 护栏的唯一标识
guardrails[].guardrail_name String 护栏的可读名称
guardrails[].guardrail_info Map (String) 护栏的附加元数据(描述、类型说明等)
guardrails[].guardrail_definition_location String 护栏定义来源:configdb
guardrails[].created_at String 护栏创建时间戳
guardrails[].updated_at String 护栏最近更新时间戳
ids List of String 所有护栏 ID 的扁平列表

所有属性均为 Computed(只读,由 Provider 从代理 API 回填),这一点可以从 data_source_guardrail.go 中的 Schema 定义得到确认——整个 Schema 里只有 Computed: true 的字段,没有任何 Required/Optional 项。

源码解析:一次 GET /guardrails/list 的完整链路

Provider 侧(Go)

数据源实现在 data_source_guardrail.go 中,核心是三个部分:

  1. 端点常量L11):
const endpointGuardrailList = "/guardrails/list"

列表查询走代理的 /guardrails/list 端点;单条查询则使用 /guardrails/{guardrail_id}/info 风格的模板端点(endpointGuardrailInfo)。

  1. API 响应结构体L49-L56),JSON 字段名与代理返回一一对应:
type guardrailListItemAPIResponse struct {
    GuardrailID                 string                 `json:"guardrail_id"`
    GuardrailName               string                 `json:"guardrail_name"`
    GuardrailInfo               map[string]interface{} `json:"guardrail_info"`
    GuardrailDefinitionLocation string                 `json:"guardrail_definition_location"`
    CreatedAt                   string                 `json:"created_at"`
    UpdatedAt                   string                 `json:"updated_at"`
}
  1. Read 函数L139-L178):通过 MakeRequest(client, "GET", endpointGuardrailList, nil) 发起无参 GET 请求,解析顶层 {"guardrails": [...]} 后逐条映射进 Terraform 状态,最终:
d.SetId("guardrails")        // 数据源 ID 固定为 "guardrails"
d.Set("guardrails", guardrails)
d.Set("ids", ids)

值得注意的是源码中单条查询函数末尾的注释(L87):

// litellm_params is intentionally not exposed: it can carry API keys.

这解释了为什么结构体里干脆没有 litellm_params 字段——即便 API 有返回,Provider 也在解码结构层面将其排除在外,与文档中“Sensitive litellm_params are not exposed”的描述相互印证。

代理侧(Python)

Provider 请求最终落在 guardrail_endpoints.py 定义的护栏 CRUD 路由上。从源码结构看,列表响应的构造函数 _get_guardrails_list_responseL99-L120)在返回前会对每条护栏的 litellm_params 做掩码处理:

masked_params = _get_masked_values(
    litellm_params,
    unmasked_length=4,
    number_of_asterisks=4,
)

也就是说存在双层防线:代理 API 本身对 litellm_params 做掩码(前 4 位可见、其余以 4 个星号代替),Terraform Provider 则干脆不把该字段纳入状态。

关于访问权限,从 litellm/proxy/_types.py 的路由分组可以看到,/guardrails/list(及其 v2 变体 /v2/guardrails/list)被列入多组只读路由白名单,其中包括面向管理/查看角色的分组,注释明确写着 “Guardrails / Policies pages (read-only views)”。可以推断:持有具备管理查看权限的 API Key 即可成功调用该数据源,而创建/注册护栏的写端点(如 /guardrails/register)则有更严格的团队/管理员级校验。

测试验证

Provider 的单元测试 data_source_guardrail_test.gohttptest 起了一个 mock 服务器来固化上述行为:

  • TestDataSourceGuardrailsRead 断言 Provider 发出的请求必须精确为 GET /guardrails/list;mock 返回两条护栏(一条 db、一条 config),测试校验 guardrails 列表长度为 2、首条 ID/名称正确,且 ids 输出为 [gid-1, gid-2]
  • 单条数据源测试 TestDataSourceGuardrailRead 同样断言请求路径为 /guardrails/gid-1/info,并验证 guardrail_definition_locationguardrail_info(如 description: "pii guard")被正确回填。

这组测试也直观展示了两种 guardrail_definition_location 取值的真实样本:同一代理实例上,db 来源的护栏(经 API 注册)与 config 来源的护栏(写在代理配置里)会混排在同一列表中,这正是文档“from both config and DB”的含义。

使用建议与注意事项

  • 区分 config 与 dbguardrail_definition_locationconfig 的护栏由代理配置文件管理,Terraform 只能通过本数据源读取它;db 来源的护栏才能配合 Provider 的 litellm_guardrail 资源做完整生命周期管理。做 IaC 盘点时可按此字段过滤,避免误以为列表中的护栏都能被 Terraform 增删。
  • 不要把敏感信息写回状态:本数据源不包含 litellm_params,因此不要试图用 Terraform 输出重建护栏的完整参数;需要凭证时仍应走代理配置或 Secret Manager。
  • 版本对齐:按 terraform/provider/README.md 的约定,Provider 版本必须与代理版本同一发行线(~> <LiteLLM 版本>);旧版 Provider(0.x 序列)与当前数据源行为不兼容,~> 0.4 之类的约束永远不会拿到新特性。
  • 只读语义:该数据源每次 plan/apply 都会重新请求 /guardrails/list,代理侧护栏变更后 Terraform 状态会自动同步,无需手动刷新。

小结

litellm_guardrails 数据源以“零参数 + 全量只读”的方式解决了护栏盘点问题:一个 data 块即可拿到全部护栏的 ID、名称、元数据、定义来源(config/db)与时间戳,并在 Provider 与代理两层实现上共同屏蔽了可能泄露密钥的 litellm_params。结合 data_source_guardrail.go 的读取逻辑、guardrail_endpoints.py 的掩码实现与 data_source_guardrail_test.go 的端点断言,你可以完整复核这条从 HCL 到代理 API 的数据链路。

登录后查看全文
热门项目推荐
相关项目推荐