web-dev-qa-db-fra.com

Tenter de déchiffrer du texte chiffré dans une fonction Lambda à l'aide de KMS entraîne un délai d'attente

Lors du déchiffrement du texte chiffré à partir de la ligne de commande à l'aide de l'AWS CLI, le texte chiffré est déchiffré sans problème:

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

Cette opération de déchiffrement fonctionne également localement lorsque vous tentez de le faire à partir d'un script 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);
  }
});

Cependant, lorsque vous essayez de le faire avec presque le même code exact que ci-dessus dans le contexte d'une fonction AWS Lambda, l'appel de la fonction entraîne un délai d'attente:

'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.`);
        }
    });
};

journal de temporisation:

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

Notes:

  • Si je commente l'appel à kms.decrypt et essayez de console.log le params ou quoi que ce soit vraiment, les valeurs sont sorties sans problème. Il semble y avoir une sorte de problème avec le kms.decrypt appel et aucune erreur réelle au-delà du délai d'attente n'est renvoyée.
  • La stratégie attachée au rôle sous lequel la fonction lambda est invoquée contient la stratégie attachée AWSLambdaVPCAccessExecutionRole, ainsi que la stratégie en ligne attachée suivante:

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"
            ]
        }
    ]
}
  • J'ai supprimé toute information d'identification du code.
23
zealoushacker

Après quelques conversations approfondies avec les gens du support AWS, qui ont été très utiles, nous avons une réponse:

La principale raison pour laquelle il y a eu un délai d'attente était due à un manque de connectivité entre la fonction Lambda et le service KMS, car le service KMS n'avait pas de point de terminaison dans le VPC où la fonction Lambda était configurée.

Pour qu'une fonction Lambda dans un VPC se connecte à tout service autre qu'Amazon S3, ce que fait ont un point d'extrémité dans le VPC, la fonction Lambda doit être située dans/associée à au moins un, mais de préférence deux sous-réseaux privés, avec leurs tables de routage comprenant une route de destination de 0.0.0.0/16 vers a NAT Gateway.

Il n'est pas possible que la fonction Lambda soit dans un sous-réseau public, avec une passerelle Internet.

Étapes pour obtenir une fonction Lambda liée à un VPC pour accéder à KMS et à tous les autres services qui n'ont pas de points de terminaison VPC:

  1. Créez ou prenez note d'un sous-réseau privé existant, qui a une entrée de table de routage pour 0.0.0.0/0 vers une passerelle NAT.
    • Si vous ne disposez pas déjà d'une passerelle NAT, d'une table de routage et du sous-réseau, comme spécifié ci-dessus, vous devrez d'abord les créer et les associer correctement.
  2. Attachez la fonction Lambda aux sous-réseaux privés ci-dessus, lors de la création de la fonction Lambda, ou modifiez la fonction Lambda pour avoir cette configuration.

Si vous suivez ces deux étapes, vous devriez pouvoir invoquer kms.encrypt et d'autres demandes provenant de votre fonction Lambda, qui nécessitent une connectivité Internet sortante/de sortie, car ces services n'ont pas de points de terminaison dans votre VPC.

Visual overview of how Lambda works within a VPC

34
zealoushacker

Les instances EC2 sont livrées avec leur propre adresse IP publique par défaut, elles n'ont donc aucun problème pour accéder aux services nécessitant un accès à Internet (tels que KMS).

Les fonctions Lambda attachées à votre VPC n'ont pas d'IP publique, donc pour accéder à un service via Internet (tel que KMS), vous avez besoin d'un NAT configuré comme décrit par zealoushacker.

4
Seth van Buren

Pour ajouter à l'excellente réponse de zealoushacker, vous devez également vérifier que les paramètres du groupe de sécurité de votre lambda ont une règle sortante qui pointe vers 0.0.0.0 et n'importe quel port.

Dans notre cas, nous fonctionnions déjà dans des sous-réseaux privés, mais nous avions limité les groupes de sécurité à notre base de données RDS.

3
Erik Schmiegelow