LiteLLM Terraform Provider:用 litellm_guardrails 数据源盘点网关上的全部护栏定义
【免费下载链接】litellmThe fastest, litest AI Gateway. Rust core with Python SDK. Call 100+ LLM APIs in OpenAI (or native) format with cost tracking, guardrails, load balancing, and logging [Bedrock, Azure, OpenAI, Anthropic, OpenAI, VertexAI, vLLM, Nvidia NIM]项目地址: https://gitcode.com/GitHub_Trending/li/litellm
本篇围绕 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 | 护栏定义来源:config或db |
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 中,核心是三个部分:
- 端点常量(L11):
const endpointGuardrailList = "/guardrails/list"列表查询走代理的/guardrails/list端点;单条查询则使用/guardrails/{guardrail_id}/info风格的模板端点(endpointGuardrailInfo)。
- 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"` }- 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 也在解码结构层面将其排除在外,与文档中“Sensitivelitellm_paramsare not exposed”的描述相互印证。
代理侧(Python)
Provider 请求最终落在 guardrail_endpoints.py 定义的护栏 CRUD 路由上。从源码结构看,列表响应的构造函数_get_guardrails_list_response(L99-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.go 用httptest起了一个 mock 服务器来固化上述行为:
TestDataSourceGuardrailsRead断言 Provider 发出的请求必须精确为GET /guardrails/list;mock 返回两条护栏(一条db、一条config),测试校验guardrails列表长度为 2、首条 ID/名称正确,且ids输出为[gid-1, gid-2];- 单条数据源测试
TestDataSourceGuardrailRead同样断言请求路径为/guardrails/gid-1/info,并验证guardrail_definition_location与guardrail_info(如description: "pii guard")被正确回填。
这组测试也直观展示了两种guardrail_definition_location取值的真实样本:同一代理实例上,db来源的护栏(经 API 注册)与config来源的护栏(写在代理配置里)会混排在同一列表中,这正是文档“from both config and DB”的含义。
使用建议与注意事项
- 区分 config 与 db:
guardrail_definition_location为config的护栏由代理配置文件管理,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 的数据链路。
【免费下载链接】litellmThe fastest, litest AI Gateway. Rust core with Python SDK. Call 100+ LLM APIs in OpenAI (or native) format with cost tracking, guardrails, load balancing, and logging [Bedrock, Azure, OpenAI, Anthropic, OpenAI, VertexAI, vLLM, Nvidia NIM]项目地址: https://gitcode.com/GitHub_Trending/li/litellm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考