无服务器框架和使用密钥管理服务(KMS)

时间:2019-02-11 13:07:59

标签: serverless-framework serverless aws-kms aws-serverless google-cloud-kms

基本上,我使用serverless框架serverless来实现允许我通过mailgun发送/接收电子邮件的功能。

为此,我在无服务器文件夹中设置了一个config.js文件。 config.js包含我的“ mailgun”功能的所有API密钥,电子邮件地址,登录名等。

我想使用Google Cloud KMS对资源config.js进行加密,因为我的敏感数据会被盗并被滥用。 加密文件为config.js.encgoogle_key_management_service

但是serverless deploy不会解密我的config.js.enc。它引发了资源/语法错误……

任何解决方案/想法如何使config.js框架中的serverless文件都能使用KMS?

我还添加了AWS标签,因为它们具有与Google Cloud类似的KMS。但是实际上,我认为真正的问题在于serverless框架,并且可以使用sls deploy命令使加密文件在无服务器部署中正常工作,但是我可能会误会。

1 个答案:

答案 0 :(得分:2)

无服务器框架似乎包含本机AWS SSM integrations

functions:
  myfunc:
    # other config
    environment:
      TWITTER_ACCESS_TOKEN: ${ssm:myFunc}

但是,正如您指出的那样,GCP上没有类似的功能,因此您需要自己滚动其中的一些功能。您可能会对Secrets in Serverless中概述的某些策略感兴趣:

您需要秘密吗?

问总是很重要-我真的需要这些秘密吗?您能否利用Cloud Provider IAM(甚至是cross-cloud OIDC)而不是将秘密注入我的应用程序中?尽可能尝试利用各种云提供的IAM解决方案。显然,仍然有很多情况需要秘密。

加密的环境变量

在启动该功能之前,您需要在本地将明文秘密加密为密文(加密的字符串)。这是gcloud的示例,但是您也可以使用API​​或其他工具,例如HashiCorp Vault

$ gcloud kms encrypt \
    --ciphertext-file=- \
    --plaintext-file=/path/to/my/secret \
    --key=my-kms-key \
    --key-ring=my-kms-keyring \
    --location=us-east4 \ 
    | base64

这将输出base64编码的加密字符串,然后将其存储在config.js中:

CiQAePa3VBJLbunLSqIJT+RS4nYiKdIaW6U69Y...

启动时,将您的应用程序配置为:

  1. Base64解码字符串
  2. 使用Cloud KMS解密密文
  3. 将纯文本存储在内存中,直到需要机密为止

我不确定您使用的是哪种语言,但这是一个nodejs示例。您可以在sethvargo/secrets-in-serverless的GitHub上找到更多示例:

const cryptoKeyID = process.env.KMS_CRYPTO_KEY_ID;

const kms = require('@google-cloud/kms');
const client = new kms.v1.KeyManagementServiceClient();

let username;
client.decrypt({
  name: cryptoKeyID,
  ciphertext: process.env.DB_USER,
}).then(res => {
  username = res[0].plaintext.toString().trim();
}).catch(err => {
  console.error(err);
});

let password;
client.decrypt({
  name: cryptoKeyID,
  ciphertext: process.env.DB_PASS,
}).then(res => {
  password = res[0].plaintext.toString().trim();
}).catch(err => {
  console.error(err);
});

exports.F = (req, res) => {
  res.send(`${username}:${password}`)
}

Google云存储

由于您使用的是GCP,另一种选择是直接使用Google云存储(GCS)来存储机密。这将消除无服务器框架中的耦合。

  1. 制造一个水桶:

    $ gsutil mb gs://${GOOGLE_CLOUD_PROJECT}-serverless-secrets
    
  2. 将存储桶设为私有:

    $ gsutil defacl set private gs://${GOOGLE_CLOUD_PROJECT}-serverless-secrets
    $ gsutil acl set -r private gs://${GOOGLE_CLOUD_PROJECT}-serverless-secrets
    
  3. 在存储桶中写入一些秘密。即使将它们作为纯文本提交,它们也会在静态时进行加密,并且通过IAM严格控制访问。

    $ gsutil -h 'Content-Type: application/json' cp - gs://${GOOGLE_CLOUD_PROJECT}-serverless-secrets/app1 <<< '{"username":"my-user", "password":"s3cr3t"}'
    

然后创建一个有权读取存储桶的服务帐户,并将该服务帐户分配给您的功能。

最后,在功能启动时从存储桶中读取(这次是Python示例):

import os
import json
from google.cloud import storage

blob = storage.Client() \
    .get_bucket(os.environ['STORAGE_BUCKET']) \
    .get_blob('app1') \
    .download_as_string()

parsed = json.loads(blob)

username = parsed['username']
password = parsed['password']

def F(request):
    return f'{username}:{password}'