node.js - 节点 Google Cloud KMS 加密似乎有效,但解密失败
问题描述
这是我的第一个 Stack Overflow 问题!
无论如何,我正在尝试使用 Cloud KMS 为我在 App Engine 中运行的节点 API 设置数据库连接机密的解密。为了让它工作,我一直在本地测试它。我使用 gcloud CLI 对机密进行加密,然后将它们上传到 Cloud Storage 存储桶(如果重要,则在与 API 不同的项目下)。在 API 中提取加密的秘密很顺利,但是当我尝试解密这些秘密时,我得到了:
Error: 3 INVALID_ARGUMENT: Decryption failed: verify that 'name' refers to the correct CryptoKey.
我检查并重新检查了我的项目 ID、密钥环 ID、密钥 ID 是否正确。
在上传到存储桶之前,我尝试在 base64 中对加密的秘密进行编码。我尝试在 API 中对编码和加密的秘密进行硬编码。这些都不起作用。
因此,为了进行完整性检查,我重写了代码以简单地加密一个字符串,然后在 API 中使用相同的 cryptoKeyPath 对其进行解密。加密似乎有效,但在解密过程中我仍然收到上述错误。
(一些云存储代码仍然存在,但在解密之前不会被使用)。
const Storage = require('@google-cloud/storage');
console.log(process.env.GOOGLE_APPLICATION_CREDENTIALS);
// if running in production we need to get the .env file from a storage bucket and decrypt.
const addSecretsToEnv = async () => {
// setup for storage bucket
const bucketName=<bucketName>;
const fileName=<fileName>;
const storage = new Storage.Storage();
const file = storage.bucket(bucketName).file(fileName);
// setup for KMS
const client = new kms.KeyManagementServiceClient();
const locationId = 'global';
const projectId = <projectId>;
const keyRingID = <keyRingID>;
const keyID = <keyID>;
try {
const formattedName = client.cryptoKeyPath(
projectId,
locationId,
keyRingID,
keyID,
);
const [result] = await client.encrypt({
name: formattedName,
plainText: 'help me!!!'
});
console.log(typeof result);
console.log(result);
const cipherText = result.ciphertext;
console.log(typeof cipherText);
console.log(cipherText);
const [decrypted] = await client.decrypt({
name: formattedName,
cipherText,
});
console.log(decrypted);
} catch(error) {
console.log(error);
}
}
module.exports = {
addSecretsToEnv
};
我通过 GOOGLE_APPLICATION_CREDENTIALS env 变量设置了身份验证,该变量指向一个服务帐户的 JSON 密钥文件,该服务帐户同时具有 Cloud KMS CryptoKey Encrypter/Decrypter 和 Cloud KMS 管理员角色(在绝望中添加了管理员角色)。
有人可以帮我吗?
提前致谢。
解决方案
资本T
是你的罪魁祸首。在 Node 中,没有值的键会扩展为它们的对象名称。例如,给定:
let foo = "banana";
传递foo
给这样的对象:
doTheThing({ foo });
扩展为:
doTheThing({ foo: foo }); // which is { foo: "banana" }
当您使用plainText
orcipherText
时,它们分别在 Node 对象中扩展为{plainText: "..."}
和。{cipherText: "..."}
不幸的是,这些不是公认的领域,但它们被默默地忽略了。因此,实际上,您不会将任何明文或密文传递给任何一个 API 调用。
加密空字符串是有效的,但解密空字符串是无效的。这就是为什么您在加密时没有收到错误的原因。
要解决此问题,请分别替换plainText
和和。我个人的建议是,您应该明确说明对函数的参数调用:cipherText
plaintext
ciphertext
const [decrypted] = await client.decrypt({
name: "projects/p/...",
ciphertext: myCiphertext,
});
否则,对变量进行细微的重命名可能会以非常晦涩的方式彻底破坏代码。
推荐阅读
- google-api - API 项目无权使用此 API。请确保在 Google Developers Console 中激活了此 API
- php - 如何从包含文件中导入 mysqli 连接?
- python - 为什么非函数可调用对象不绑定到类实例?
- reactjs - 映射数据并创建输入字段,但为什么我可以输入除一个之外的所有字段?
- javascript - 铬画布上悲伤的脸
- python - Keras深度学习准确率100%的问题
- go - 为什么 GDB 显示大地图的所有零值
- devextreme - DevExtreme Angular DataGrid - 自定义分组面板和操作
- java - 内部地图和平面地图如何在 java 8 中工作
- ruby - 快速将字符串拆分为多个数组