AI Gateway 允许你安全地将日志导出到外部存储位置,在那里你可以解密和处理它们。 你可以在 Cloudflare 仪表板 ↗ 设置中开启和关闭 Workers Logpush。此产品在 Workers Paid 计划上可用。有关定价信息,请参阅定价。
本指南说明如何为 AI Gateway 设置 Workers Logpush、生成用于加密的 RSA 密钥对,以及在收到日志后解密日志。
每个 gateway 最多可存储 1000 万条日志。如果达到限制,新日志将停止保存,也不会通过 Workers Logpush 导出。要继续保存和导出日志,必须删除旧日志以释放空间。Workers Logpush 限制为 4 个作业,每条日志最大请求大小为 1 MB。
我们采用混合加密模型以提高效率和安全性。首先,为每条日志生成 AES 密钥。此 AES 密钥实际加密大部分数据,因其在处理大型数据集时的速度和安全性而被选用。
现在,为了安全共享此 AES 密钥,我们使用 RSA 加密。过程如下:AES 密钥虽然轻量,但需要安全传输给接收方。我们使用接收方的 RSA 公钥加密此密钥。此步骤利用 RSA 在安全密钥分发方面的优势,确保只有拥有相应 RSA 私钥的人才能解密和使用 AES 密钥。
加密后,AES 加密的数据和 RSA 加密的 AES 密钥一起发送。到达后,接收方系统使用 RSA 私钥解密 AES 密钥。AES 密钥可访问后,解密主要数据负载就很简单了。
此方法结合了两者的优势:AES 的数据加密效率与 RSA 的安全密钥交换能力,确保在整个数据生命周期中最佳地维护数据完整性、机密性和性能。
要为 AI Gateway 配置 Workers Logpush,请按照以下步骤操作:
你需要生成密钥对来加密和解密日志。此脚本将输出 RSA privateKey 和 publicKey。请安全保管私钥,它将用于解密日志。以下是使用 Node.js 和 OpenSSL 生成密钥的示例脚本。
const crypto = require("crypto");
const { privateKey, publicKey } = crypto.generateKeyPairSync("rsa", {
modulusLength: 4096,
publicKeyEncoding: {
type: "spki",
format: "pem",
},
privateKeyEncoding: {
type: "pkcs8",
format: "pem",
},
});
console.log(publicKey);
console.log(privateKey);在终端上执行以下代码运行脚本。将 file name 替换为你的 JavaScript 文件名。
node {file name}-
生成私钥: 使用以下命令生成 RSA 私钥:
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:4096 -
生成公钥: 生成私钥后,可以使用以下命令提取相应的公钥:
openssl rsa -pubout -in private_key.pem -out public_key.pem
生成密钥对后,将公钥上传到 AI Gateway 设置。此密钥将用于加密日志。要启用 Workers Logpush,需要为该 gateway 启用日志记录。
要设置 Logpush,请参阅 Logpush 文档。
配置 Workers Logpush 后,日志将使用你上传的公钥加密发送。要访问数据,你需要使用私钥解密。日志将发送到你选择的对象存储提供商。
要解密来自 AI Gateway 的加密日志正文和元数据,可以使用以下 Node.js 脚本或 OpenSSL:
要解密来自 AI Gateway 的加密日志正文和元数据,将日志下载到文件夹,在此示例中命名为 my_log.log.gz。
然后将此 JavaScript 文件复制到同一文件夹,并将私钥放在顶部变量中。
const privateKeyStr = `-----BEGIN RSA PRIVATE KEY-----
....
-----END RSA PRIVATE KEY-----`;
const crypto = require("crypto");
const privateKey = crypto.createPrivateKey(privateKeyStr);
const fs = require("fs");
const zlib = require("zlib");
const readline = require("readline");
async function importAESGCMKey(keyBuffer) {
try {
// Ensure the key length is valid for AES
if ([128, 192, 256].includes(256)) {
return await crypto.webcrypto.subtle.importKey(
"raw",
keyBuffer,
{
name: "AES-GCM",
length: 256,
},
true, // Whether the key is extractable (true in this case to allow for export later if needed)
["encrypt", "decrypt"], // Use for encryption and decryption
);
} else {
throw new Error("Invalid AES key length. Must be 128, 12, or 256 bits.");
}
} catch (error) {
console.error("Failed to import key:", error);
throw error;
}
}
async function decryptData(encryptedData, aesKey, iv) {
const decryptedData = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: iv },
aesKey,
encryptedData,
);
return new TextDecoder().decode(decryptedData);
}
async function decryptBase64(privateKey, data) {
if (data.key === undefined) {
return data;
}
const aesKeyBuf = crypto.privateDecrypt(
{
key: privateKey,
oaepHash: "SHA256",
},
Buffer.from(data.key, "base64"),
);
const aesKey = await importAESGCMKey(aesKeyBuf);
const decryptedData = await decryptData(
Buffer.from(data.data, "base64"),
aesKey,
Buffer.from(data.iv, "base64"),
);
return decryptedData.toString();
}
async function run() {
let lineReader = readline.createInterface({
input: fs.createReadStream("my_log.log.gz").pipe(zlib.createGunzip()),
});
lineReader.on("line", async (line) => {
line = JSON.parse(line);
const { Metadata, RequestBody, ResponseBody, ...remaining } = line;
console.log({
...remaining,
Metadata: await decryptBase64(privateKey, Metadata),
RequestBody: await decryptBase64(privateKey, RequestBody),
ResponseBody: await decryptBase64(privateKey, ResponseBody),
});
console.log("--");
});
}
run();在终端上执行以下代码运行脚本。将 file name 替换为你的 JavaScript 文件名。
node {file name}该脚本读取加密日志文件 (my_log.log.gz),解密元数据、请求正文和响应正文,并打印解密后的数据。
请确保将 privateKey 变量替换为你在步骤 1 中生成的实际 RSA 私钥。
- 使用私钥解密加密日志文件。
假设日志使用公钥(例如 public_key.pem)加密,你可以使用私钥(private_key.pem)解密日志文件。
例如,如果加密日志在名为 encrypted_logs.bin 的文件中,可以这样解密:
openssl rsautl -decrypt -inkey private_key.pem -in encrypted_logs.bin -out decrypted_logs.txt-decrypt告诉 OpenSSL 我们要解密文件。-inkey private_key.pem指定用于解密日志的私钥。-in encrypted_logs.bin是加密日志文件。-out decrypted_logs.txt解密后的日志将保存到此文件。
- 查看解密后的日志 解密后,可以通过运行以下命令查看日志:
cat decrypted_logs.txt此命令将在终端输出解密后的日志。