【问题标题】:Node Google Cloud KMS encryption seems to work but decryption fails节点 Google Cloud KMS 加密似乎有效,但解密失败
【发布时间】:2019-12-14 06:23:20
【问题描述】:

这是我的第一个 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 Admin 角色(在绝望中添加了管理员角色)。

有人可以帮帮我吗?

提前致谢。

【问题讨论】:

  • 您是否创建了非对称密钥的对称密钥?如果它是对称的(应该是对称的),我认为您将 Node.js 打造成 Node.js。将plainTextcipherText 中的大写“T”小写(使它们成为plaintextciphertext 反射。另请参阅:github.com/sethvargo/secrets-in-serverless
  • 您也可能对cloud.google.com/secret-manager感兴趣
  • 它是一个对称密钥。哇。没错,就是大写。但我想这意味着加密步骤不起作用。这对我来说绝对不明显。感谢您的帮助,@sethvargo。另外,我想我对 Node 的了解还不够,您可以扩展您的“Node.js 是 Node.js”的评论吗?
  • @sethvargo:很棒的答案! Node.js 的陷阱很无聊!!
  • 我在答案中添加了更多细节。

标签: node.js encryption google-cloud-platform google-cloud-kms


【解决方案1】:

首都T是你的罪魁祸首。在 Node 中,没有值的键会扩展为它们的对象名称。例如,给定:

let foo = "banana";

foo 传递给这样的对象:

doTheThing({ foo });

扩展为:

doTheThing({ foo: foo }); // which is { foo: "banana" }

当您使用plainTextcipherText 时,它们在Node 对象中分别扩展为{plainText: "..."}{cipherText: "..."}。不幸的是,这些不是公认的领域,但它们被默默地忽略了。因此,实际上,您不会将任何明文或密文传递给任一 API 调用。

加密空字符串有效的,但解密空字符串不是。这就是您在加密时没有收到错误消息的原因。

要解决此问题,请将 plainTextcipherText 分别替换为 plaintextciphertext。我个人建议您改为明确说明对函数的参数调用:

const [decrypted] = await client.decrypt({
  name: "projects/p/...",  
  ciphertext: myCiphertext,
});

否则,对变量进行细微的重命名可能会以非常晦涩的方式严重破坏代码。

【讨论】:

  • 是的,将它们更改为全部小写有效,但我不完全明白为什么。您的回答帮助我了解了之前发生的事情。我感谢您的帮助! :)
猜你喜欢
  • 2018-06-18
  • 2018-01-23
  • 2013-01-14
  • 2019-03-08
  • 1970-01-01
  • 1970-01-01
  • 2021-02-09
  • 1970-01-01
  • 2020-08-11
相关资源
最近更新 更多