15

當從使用AWS CLI命令行解密的密文,密文被解密沒有問題:試圖使用超時KMS結果lambda函數內解密的密文

$ aws kms decrypt --ciphertext-blob fileb://encrypted-secrets --output text --query Plaintext --region us-east-1 | base64 --decode > decryped-secrets 

這解密操作也試圖在本地工作從JS腳本這樣做:

#!/usr/local/bin/node 

const fs = require('fs'); 
const AWS = require('aws-sdk'); 
const kms = new AWS.KMS({region:'us-east-1'}); 

const secretPath = './encrypted-secrets'; 
const encryptedSecret = fs.readFileSync(secretPath); 

const params = { 
     CiphertextBlob: encryptedSecret 
}; 

kms.decrypt(params, function(err, data) { 
    if (err) { 
    console.log(err, err.stack); 
    } else { 
    const decryptedScret = data['Plaintext'].toString(); 
    console.log('decrypted secret', decryptedScret); 
    } 
}); 

但是,試圖與幾乎相同的確切的代碼如上述從AWS lambda函數,在超時的函數結果的調用的上下文內這樣做時:

'use strict'; 

const zlib = require('zlib'); 
const mysql = require('mysql'); 
const fs = require('fs'); 
const AWS = require('aws-sdk'); 
const kms = new AWS.KMS({region:'us-east-1'}); 

const secretPath = './encrypted-secrets'; 
const encryptedSecret = fs.readFileSync(secretPath); 

const params = { 
    CiphertextBlob: encryptedSecret 
}; 

exports.handler = (event, context, callback) => { 
    kms.decrypt(params, (err, data) => { 
     if (err) { 
      console.log(err, err.stack); 
      return callback(err); 
     } else { 
      const decryptedScret = data['Plaintext'].toString(); 
      console.log('decrypted secret', decryptedScret); 
      return callback(null, `Successfully processed ${parsed.logEvents.length} log events.`); 
     } 
    }); 
}; 

超時日誌:

START RequestId: start-request-id-redacted Version: $LATEST 
END RequestId: end-request-id-redacted 
REPORT RequestId: report-requested-id-redacted Duration: 10002.43 ms Billed Duration: 10000 ms Memory Size: 128 MB Max Memory Used: 18 MB 
2016-11-13T19:22:28.774Z task-id-redacted Task timed out after 10.00 seconds 

注:

  • 如果我註釋掉調用kms.decrypt,並試圖console.logparams或任何真正的價值輸出,而不的問題。 kms.decrypt調用似乎存在某種問題,並且不會返回超時超時的實際錯誤。
  • 附着在其下lambda函數被調用的作用策略包含附加的政策AWSLambdaVPCAccessExecutionRole,也是下面連接的內聯政策:

policygen-lambda_basic_execution_and_kms_decrypt-201611131221

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
     { 
      "Sid": "sid-redacted", 
      "Effect": "Allow", 
      "Action": [ 
       "kms:Decrypt" 
      ], 
      "Resource": [ 
       "arn:aws:kms:us-east-1:account-redacted:key/key-id-redacted" 
      ] 
     } 
    ] 
} 
  • 我已經編輯代碼中的任何標識信息。

回答

28

與AWS支持人員,其中非常有幫助的一些深入交談後,我們有一個答案:

爲什麼出現超時的主要原因是由於來自lambda函數中缺少連接到KMS服務,因爲KMS服務在配置了Lambda功能的VPC中沒有端點。

爲了用於在VPC lambda函數連接到除亞馬遜S3其它任何服務,確實有一個端點在VPC,拉姆達函數必須位於/與至少一個相關聯的,但最好是兩個私有子網,其路由表中包含目的地路由0.0.0.0/16到NAT網關。

它是不是可能使Lambda函數位於具有Internet網關的公有子網中。

步驟來得到一個VPC-LAMBDA約束函數來訪問KMS和所有其他服務沒有終點VPC:

  1. 創建或利用現有的專用子網,其中有一個路由表項的注意事項爲0.0.0.0/0添加到NAT網關。
    • 如果您還沒有NAT網關,路由表和子網,如上所述,您必須首先適當地創建並相互關聯它們。
  2. 在創建Lambda函數時將Lambda函數附加到上面的專用子網,或者編輯Lambda函數以獲得該配置。

如果按照這兩個步驟,你應該能夠從您的lambda函數中調用kms.encrypt和其他請求,這需要出站/出互聯網連接,由於這些服務上的VPC內沒有終點。

Visual overview of how Lambda works within a VPC

+1

我們遇到了同樣的問題,這真的很有幫助! AWS支持人員解釋了爲什麼公共VPC子網中的EC2實例能夠訪問KMS /其他服務,但Lambda函數不是? –

+1

他們沒有具體解釋,但是基於我對Lambda函數如何實例化的理解,這是由於Lambda函數位於他們自己的VPC中的臨時容器中。 – zealoushacker

+0

在圖中,互聯網網關被描繪爲在VPC子網中,這是非常的。 Internet網關與整個VPC相關聯,但不在任何給定的子網中。 –

2

EC2實例皆預設自己的公網IP,使他們有沒有問題訪問需要訪問互聯網(如KMS)的任何服務。

附加到您的VPC的Lambda功能沒有公共IP,因此通過互聯網(例如KMS)訪問服務時,您需要按照zealoushacker的描述設置NAT。

+0

這取決於您對默認VPC中的EC2實例或「EC2 Classic」帳戶中的EC2實例。但是,如果您創建了自己的VPC,實例默認情況下可能不會獲得公共IP,並且需要NAT網關 - 這是創建VPC時的設置。 – RichVel

2

要加入zealoushacker的優秀答案,您還應該檢查您的lambda安全組設置是否有指向0.0.0.0和任何端口的出站規則。

在我們的案例中,我們已經在專用子網中運行,但是已經將安全組限制在我們的RDS數據庫中。