服务网格ASM作为云原生环境下的网络基础设施,提供了丰富的可扩展能力。通过一些自定义的插件,您可以在网格级别精准限制每一个应用(包括网关以及普通业务Pod)调用大模型的行为,防止敏感信息泄漏。本文将演示如何利用Wasm插件在网格全局强制保护对LLM的调用行为。
背景信息
随着LLM(Large Language Model)的快速发展,各个行业逐渐看到了AI大规模落地的曙光。自MaaS(模型即服务)被提出以来,国内外厂商相继推出了自己的模型服务,进一步加速了大模型在实际场景中的落地进展。LLM正在成为各个企业所依赖的一项基础服务。
站在大模型使用方的角度,大模型引入的安全风险是一个无法回避的问题。例如API_KEY泄漏给调用方,可能会造成API滥用,使用成本增加;再比如企业敏感信息被无意间发送给大模型服务,由于大模型服务的控制权属于外部厂商,这些数据将变得不再安全。鉴于此,我们迫切需要从平台层面提供全局的安全保护,以避免不必要的损失。
ASM支持使用Wasm来扩展网格代理的功能,您可以使用Go、Rust、C++等语言开发并编译成Wasm的二进制文件,之后打包成镜像上传至镜像仓库中,可以动态下发至网格代理(网关、Sidecar)中对请求进行操作。Wasm插件是完全热插拔的,不需要重新部署应用,也不会影响已有请求。并且Wasm插件运行在沙箱之中,具有良好的隔离性,不会影响代理本身。加上Wasm较低的开发门槛(相较于开发原生Envoy HTTP Filter),ASM优先选用基于Go语言开发LLMProxy插件。
本文所涉及的插件代码已开源,您可以自行下载使用或定制自己的LLM插件,具体信息,请参见asm-labs/wasm-llm-proxy at main · AliyunContainerService/asm-labs。
前提条件
添加集群到ASM实例,且ASM实例版本为1.18及以上。
已启用Sidecar注入。具体操作,请参见配置Sidecar注入策略。
已经开通模型服务灵积,并且获取了可用的API_KEY。具体操作,请参见API-KEY的获取与配置。
示例概述
本文主要演示能力如下:
Sidecar或网关为LLM请求动态添加API_KEY,业务应用无需自行维护API_KEY。动态配置API_KEY,防止API_KEY泄漏。
在Sidecar或网关中配置自定义判别规则,禁止携带敏感信息的LLM请求离开Pod被发往外部LLM服务。
调用私有模型对LLM请求进行识别,更精准地判断请求是否携带敏感信息,以此决定是否放行请求。私有模型只用来判别请求是否包含敏感信息,在保证准确率的情况下,可以选择尽可能小的模型。
没有接入ASM之前如果需要访问外部的HTTPS服务,需要直接发起HTTPS请求,并且在应用中维护与LLM服务的TCP长连接,如果维护不当,可能会导致频繁建连影响性能。
接入网格后,您可以在应用中直接使用HTTP协议发起请求,网格代理可以将HTTP请求升级至HTTPS。由Envoy维护HTTPS连接,能够有效减少TLS握手次数从而提升性能。
演示的最终效果是:业务容器使用HTTP协议发起请求,请求中无需携带LLM的API_KEY。之后这个请求进入Sidecar,Sidecar为这个请求添加API_KEY,然后进行敏感信息校验,根据校验结果允许或者拒绝请求通过,之后将HTTP协议升级为HTTPS协议发往外部LLM服务。
演示的LLM服务基于阿里云模型服务灵积 DashScope,我们将使用标准的HTTP接口来调用DashScope,相关文档请参见通过HTTP接口调用。
示例演示
步骤一:部署客户端应用
通过kubectl连接到ASM实例添加的Kubernetes集群,使用以下内容创建sleep.yaml
执行以下命令部署Sleep应用。
kubectl apply -f sleep.yaml
步骤二:创建ServiceEntry以及DestinationRule
由于LLM服务在网格外部,想要外部服务可以被网格管理,您需要手动创建一个集群外服务(ServiceEntry)将服务注册到网格中。具体操作,请参见创建集群外服务。
在这里,我们使用ServiceEntry将模型服务灵积注册至ASM中。对应YAML如下:
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: dashscope
namespace: default
spec:
hosts:
- dashscope.aliyuncs.com
ports:
- name: http-port
number: 80
protocol: HTTP
targetPort: 443 # 和Destination配合使用,用于将HTTP协议升级为HTTPS
- name: https-port
number: 443
protocol: HTTPS
resolution: DNS
为了让Sidecar能够将访问灵积服务80端口的HTTP协议升级为HTTPS,这里需要再配置一个对应的目标规则,对应YAML如下:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: dashscope
namespace: default
spec:
host: dashscope.aliyuncs.com
trafficPolicy:
portLevelSettings:
- port:
number: 80
tls:
mode: SIMPLE
依次执行以下命令,确认Sidecar已经完成HTTP到HTTPS的协议升级。
export API_KEY=${dashscope的API_KEY} # 请替换为实际的API KEY
kubectl exec deploy/sleep -- curl -v 'http://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions' \
--header "Authorization: Bearer ${API_KEY}" \
--header 'Content-Type: application/json' \
--header 'user: test' \
--data '{
"model": "qwen-turbo",
"messages": [
{"role": "user", "content": "你是谁"}
],
"stream": false
}'
预期输出:
{"choices":[{"message":{"role":"assistant","content":"我是来自阿里云的大规模语言模型,我叫通义千问。"},"finish_reason":"stop","index":0,"logprobs":null}],"object":"chat.completion","usage":{"prompt_tokens":10,"completion_tokens":16,"total_tokens":26},"created":xxxxxxxx,"system_fingerprint":null,"model":"qwen-turbo","id":"xxxxxxxxxxxxxxxxxx"}
步骤三:配置LLMProxy插件
使用以下内容创建WasmPlugin.yaml。
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
name: asm-llm-proxy
namespace: default
spec:
imagePullPolicy: Always
phase: AUTHN
selector:
matchLabels:
app: sleep
url: registry-cn-hangzhou.ack.aliyuncs.com/test/asm-llm-proxy:v0.2
pluginConfig:
api_key: ${dashscope的API_KEY}
deny_patterns:
- .*账号.* # 禁止包含“账号”两个字的message被发往外部大模型
hosts:
- dashscope.aliyuncs.com # 该插件只对host为dashscope.aliyuncs.com的请求生效
intelligent_guard: # 配置一个私有LLM服务,对请求进行敏感信息验证。
# 本文为了验证方便,依然调用灵积服务来对请求进行验证。
api_key: ${dashscope的API_KEY}
host: dashscope.aliyuncs.com
model: qwen-turbo
path: /compatible-mode/v1/chat/completions
port: 80 # serviceentry中的HTTP端口
海外镜像地址请使用:registry-cn-hongkong.ack.aliyuncs.com/test/asm-llm-proxy:v0.2。
pluginConfig
配置说明。
参数 | 子参数 | 说明 |
api_key | \ | dashscope的API_KEY。配置后,应用发起HTTP请求时无需携带API_KEY,可以根据这里的配置动态添加,降低API_KEY泄漏的风险。如果API_KEY需要轮转,直接修改YAML中的配置即可,无需修改应用。 |
deny_patterns | \ | 正则表达式列表,用于匹配LLM请求中的message。匹配到的请求将会被拒绝。还支持配置 |
hosts | \ | host列表,只有发往这些host的请求才会被LLMProxy处理。避免其他普通请求被误处理。 |
intelligent_guard | api_key | dashscope的API_KEY。 |
host | 灵积服务的host。 | |
model | 要调用的大模型种类,比如qwen-turbo、qwen-max、baichuan2-7b-chat-v1等。这里可以根据需求进行定制,确保判别准确率的同时,尽量选择延迟低的大模型。 | |
path | LLM请求的path。 | |
port | 私有LLM服务的端口,需要和ServiceEntry中的HTTP端口一致。 |
intelligent_guard
是OpenAI的标准接口,用于判定发往LLM模型的请求是否包含敏感信息。如果被私有大模型判定为包含敏感信息,请求将会被拒绝,并返回具体原因。本示例中为了演示方便,仍旧调用了模型服务灵积。
执行以下命令,创建WasmPlugin。
kubectl apply -f WasmPlugin.yaml
示例测试
执行以下命令,测试不携带API_KEY的请求可以正常访问LLM服务。
kubectl exec deploy/sleep -- curl 'http://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions' \ --header 'Content-Type: application/json' \ --data '{ "model": "qwen-turbo", "messages": [ {"role": "user", "content": "你是谁"} ], "stream": false }'
预期输出:
{"choices":[{"message":{"role":"assistant","content":"我是来自阿里云的大规模语言模型,我叫通义千问。"},"finish_reason":"stop","index":0,"logprobs":null}],"object":"chat.completion","usage":{"prompt_tokens":10,"completion_tokens":16,"total_tokens":26},"created":xxxxxxx,"system_fingerprint":null,"model":"qwen-turbo","id":"xxxxxxxxx"}
执行以下命令,测试携带敏感词“账号”的请求会被拒绝。
kubectl exec deploy/sleep -- curl 'http://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions' \ --header 'Content-Type: application/json' \ --data '{ "model": "qwen-turbo", "messages": [ {"role": "user", "content": "我喜欢吃豆沙粽子,我的QQ账号是1111111"} ], "stream": false }'
预期输出:
request was denied by asm llm proxy
测试携带了敏感信息,但是不在deny_patterns中。观察
intelligent_guard
能发识别敏感信息并拦截请求。kubectl exec deploy/sleep -- curl -s 'http://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions' \ --header 'Content-Type: application/json' \ --data '{ "model": "qwen-turbo", "messages": [ {"role": "user", "content": "我们公司将会在9月10日举行内部高级别会议,会议主题是如何更好的服务客户,请给我一份会议开场白。"} ], "stream": false }'
输出如下:
可以看到,LLM模型成功识别到当前请求中可能存在敏感信息,LLMProxy插件会拒绝该请求继续发往外部LLM服务。在生产环境中,判定请求是否有敏感信息的模型需要私有化部署,这样可以确保敏感信息不泄漏。
总结
本文围绕的主要问题是:如何在使用外部LLM服务时更好地保障企业的数据安全,主要有两方面:
如何保障调用大模型时的API_KEY的安全?
如何确保调用大模型时,不会发生数据泄漏?
通过ASM的LLMProxy插件,您可以更加优雅地实现API_KEY的轮转,并且能够精准、智能地限制敏感信息的外流。这一切都得益于ASM通过Wasm提供的可扩展能力。目前我们已经将这一插件的代码开源(asm-labs/wasm-llm-proxy at main · AliyunContainerService/asm-labs),欢迎大家体验。如果您有其他的通用需求,可以向我们提出issue,我们会持续更新。