5
votes

Comment accéder au magasin de paramètres aws à partir d'un lambda à l'aide de node.js et aws-sdk

J'ai créé un modèle de formation lambda et cloud qui accorde un accès lambda au magasin de paramètres et au gestionnaire de secrets. Lorsque je teste le lambda, j'ai les fonctions suivantes en dehors de la fonction export.handler:

exports.handler = (event,ctx, callback){
done = async()=>{
 console.log('this is the event' + JSON.stringify(event));
    sfdcEndPointParam =  { Path : '/PartnerBanking/Service/SfdcEndpoint'};
    let myendpoint = await getParameterFromStoreAsync(sfdcEndPointParam);

    console.log('### endpoint path: ' + JSON.stringify(myendpoint));}
}
callback(null, done());

servmgr est instancié sous la forme var servmgr = new AWS.SSM ();

Quand j'appelle cette fonction depuis la fonction export.handler, je le fais comme:

### endpoint path: {"Parameters":[]}

Dans le lambda j'ai la fonction récupère le paramètre défini en dehors de la fonction export.handler bt enveloppée dans une promesse.

Quand j'exécute / teste ce lambda l'objet retourné est toujours indéfini ... je récupère Parameters [] mais non valeurs.

const getParameterFromStoreAsync = (param) => {
    return new Promise((resolve, reject) => {
        servmgr.getParametersByPath(param, (err, data) => {
            if(err){
                reject(console.log('Error getting parameter: ' + err, err.stack));
            } 
            return resolve(data);
        });
    });
};

exports.handler = async(event, ctx, callback) => {

console.log('INFO[lambda]: Event: [' + JSON.stringify(event, null, 2) + ']');

    console.log('this is the event' + JSON.stringify(event));
    sfdcEndPointParam =  { Path : '/PartnerBanking/Service/SfdcEndpoint'};
    let myendpoint = await getParameterFromStoreAsync(sfdcEndPointParam);

    console.log('### endpoint path: ' + JSON.stringify(myendpoint));

done = ()=>{}
callback(null, done());
};

Comment obtenir les valeurs de paramètres renvoyées à un lambda au moment de l'exécution? p>

Je vois toujours un tableau vide renvoyé dans mes tests:

2019-02-20T21:42:41.340Z    2684fe88-d552-4560-a477-6761f2de6717    ++ /myPath/Service/serviceEndpoint
2019-02-20T21:42:41.452Z    2684fe88-d552-4560-a477-6761f2de6717    ---- result: {"Parameters":[]}

J'ai également déplacé la fonction dans le rappel comme

myFirstParam =  { Path : '/myPath/Service/servicesEndpoint'};

let endpointResult = getParameterFromStore(myFirstParam);

Même résultat ... tableau vide. Avez-vous d'autres choses à essayer?


0 commentaires

3 Réponses :


9
votes

C'est parce que votre getParameterFromStore retourne avant que votre code then () ne soit exécuté, donc parameterResult est indéfini . Si vous ne voulez pas trop changer votre code, je vous renvoie la promesse que vous créez, comme ceci:

'use strict';

const AWS = require('aws-sdk')

AWS.config.update({
  region: 'us-east-1'
})

const parameterStore = new AWS.SSM()

const getParam = param => {
  return new Promise((res, rej) => {
    parameterStore.getParameter({
      Name: param
    }, (err, data) => {
        if (err) {
          return rej(err)
        }
        return res(data)
    })
  })
}

module.exports.get = async (event, context) => {
  const param = await getParam('MyTestParameter')
  console.log(param);
  return {
    statusCode: 200,
    body: JSON.stringify(param)
  };
};

};

Et enfin, sur votre fonction client, vous pouvez obtenir le résultat comme ceci:

const getParameterFromStore = param => {
    return new Promise((resolve, reject) => {
        console.log('++ ' + param.Path);
        servmgr.getParametersByPath(param, (err, data) => {
            if (err) {
                console.log('Error getting parameter: ' + err, err.stack)
                return reject(err);
            }
            return resolve(data);
        });
    })
}

exports.handler = async (event) => {
   const endpointResult = await getParameterFromStore(event.someAttributeFromTheEventThatYouWantToUse)

   console.log(endpointResult)
};

Lors du codage dans NodeJS, cependant, je vous recommande fortement d'utiliser async / await à la place, vous pourrez donc échapper à l'enfer de la promesse (changer la promesse après la promesse afin de réaliser quelque chose de" synchrone ")

Lorsque vous utilisez async / await, vous pouvez concevoir votre code comme s'il était synchrone. Voici une version refactorisée de votre exemple, utilisant async / await ainsi que les fonctions fléchées:

const myFirstParam =  { Path : '/myPath/Service/servicesEndpoint'}
getParameterFromStore(myFirstParam).then(console.log)

EDIT : After l'OP a résolu le premier problème, j'ai créé un exemple de travail par moi-même. Il s'est avéré que la façon dont l'OP invoquait l'API était incorrecte.

Voici l'exemple de travail complet:

function getParameterFromStore(param){
return new Promise(function(resolve, reject){
    console.log('++ ' + param.Path);
    servmgr.getParametersByPath(param, function(err, data){
        if(err){
            reject(console.log('Error getting parameter: ' + err, err.stack));
        } else {
            resolve(data);
        }
    });
});

Attention au Nom qui doit être fourni dans le cadre de l'appel d'API à la méthode ServiceManager.getAttribute.

Cet attribut est indiqué dans le docs

J'ai exécuté ceci moi-même et voici la sortie dans CloudWatch Logs: p >

 entrez la description de l'image ici

Comme vous pouvez le voir, la valeur a été renvoyée avec succès.

J'espère que cela vous aidera!

p>


6 commentaires

Merci Thales, j'ai mis à jour ma question. Changer mon implémentation pour utiliser async / await renvoie toujours un tableau vide.


Pourriez-vous s'il vous plaît mettre à jour la question avec votre gestionnaire? Cela peut maintenant être quelque chose à voir avec les portées.


@rlcrews J'ai mis à jour ma réponse avec un exemple fonctionnel. J'espère que cela t'aides!


Cela semble avoir été le problème de l'omission du {Name: param} dans l'appel. Merci pour les conseils


Vous pouvez également utiliser l'API de promesse intégrée parameterStore.getParameter (...). Promise () , au lieu de gérer la new Promise () par vous-même. (J'ai également écrit un microframework pour aider les développeurs à récupérer des secrets sans traiter directement l'API de bas niveau: laconiajs.io/docs/guides/retrieving-secrets . Avis de non-responsabilité: je suis l'auteur).


même si cela ne fait pas partie de la question de l'OP - Cela peut aider quelqu'un qui cherche à obtenir des valeurs déchiffrées pour les paramètres de chaîne sécurisés: parameterStore.getParameter ({Name: param, WithDecryption: true} ....



1
votes

Si votre lambda est déployé sur VPC, assurez-vous que le groupe de sécurité y est attaché et que le trafic sortant est autorisé. Il pourra accéder automatiquement au magasin de paramètres.

https://aws.amazon.com/ premiumsupport / centre de connaissances / lambda-vpc-parameter-store /


0 commentaires

0
votes

Une solution plus simple serait:

const getParameterFromStore = (params) => servmgr.getParametersByPath(params).promise();

const myFirstParam =  { Path : '/myPath/Service'};
getParameterFromStore(myFirstParam).then(console.log);

Comme vous pouvez le voir, le SDK lui-même fournit une fonctionnalité utilitaire que vous pouvez utiliser en fonction de vos besoins pour une utilisation asynchrone ou syncronieuse.

J'espère que cela vous aidera.

  • m


0 commentaires