Funciones SW AWS Lambda de ejemplo para reglas de AWS Config (Node.js) - AWS Config

Si proporcionásemos una traducción de la versión en inglés de la guía, prevalecerá la versión en inglés de la guía si hubiese algún conflicto. La traducción se proporciona mediante traducción automática.

Funciones SW AWS Lambda de ejemplo para reglas de AWS Config (Node.js)

AWS Lambda ejecuta funciones en respuesta a eventos que publican los servicios de AWS. La función de una regla de configuración personalizada recibe un evento que publica AWS Config y, a continuación, la función utiliza los datos que recibe del evento y que recupera de la API de AWS Config para evaluar la conformidad con la regla. Las operaciones que hay en una función de una regla de configuración son diferentes en función de si realiza una evaluación que se activa por los cambios en la configuración o se activa de forma periódica.

Para obtener más información sobre los patrones comunes de las funciones AWS Lambda, consulte Modelo de programación en la AWS Lambda Developer Guide.

Función de ejemplo para evaluaciones activadas por cambios de configuración

AWS Config invoca una función, como en el siguiente ejemplo, cuando detecta un cambio de configuración en un recurso que se encuentra dentro del ámbito de una regla personalizada.

Si utiliza la consola de AWS Config para crear una regla que esté asociada a una función como la de este ejemplo, elija Configuration changes (Cambios de configuración) como tipo de disparador. Si utiliza la API de AWS Config o AWS CLI para crear la regla, establezca el atributo MessageType en ConfigurationItemChangeNotification y OversizedConfigurationItemChangeNotification. Estos ajustes permiten activar la regla cuando AWS Config genera un elemento de configuración o un elemento de configuración sobredimensionado como resultado de un cambio de recurso.

En este ejemplo, se evalúan los recursos y se comprueba si las instancias coinciden con el tipo de recurso: AWS::EC2::Instance. La regla se activa cuando AWS Config genera un elemento de configuración o una notificación de un elemento de configuración sobredimensionado.

'use strict'; const aws = require('aws-sdk'); const config = new aws.ConfigService(); // Helper function used to validate input function checkDefined(reference, referenceName) { if (!reference) { throw new Error(`Error: ${referenceName} is not defined`); } return reference; } // Check whether the message type is OversizedConfigurationItemChangeNotification, function isOverSizedChangeNotification(messageType) { checkDefined(messageType, 'messageType'); return messageType === 'OversizedConfigurationItemChangeNotification'; } // Get the configurationItem for the resource using the getResourceConfigHistory API. function getConfiguration(resourceType, resourceId, configurationCaptureTime, callback) { config.getResourceConfigHistory({ resourceType, resourceId, laterTime: new Date(configurationCaptureTime), limit: 1 }, (err, data) => { if (err) { callback(err, null); } const configurationItem = data.configurationItems[0]; callback(null, configurationItem); }); } // Convert the oversized configuration item from the API model to the original invocation model. function convertApiConfiguration(apiConfiguration) { apiConfiguration.awsAccountId = apiConfiguration.accountId; apiConfiguration.ARN = apiConfiguration.arn; apiConfiguration.configurationStateMd5Hash = apiConfiguration.configurationItemMD5Hash; apiConfiguration.configurationItemVersion = apiConfiguration.version; apiConfiguration.configuration = JSON.parse(apiConfiguration.configuration); if ({}.hasOwnProperty.call(apiConfiguration, 'relationships')) { for (let i = 0; i < apiConfiguration.relationships.length; i++) { apiConfiguration.relationships[i].name = apiConfiguration.relationships[i].relationshipName; } } return apiConfiguration; } // Based on the message type, get the configuration item either from the configurationItem object in the invoking event or with the getResourceConfigHistory API in the getConfiguration function. function getConfigurationItem(invokingEvent, callback) { checkDefined(invokingEvent, 'invokingEvent'); if (isOverSizedChangeNotification(invokingEvent.messageType)) { const configurationItemSummary = checkDefined(invokingEvent.configurationItemSummary, 'configurationItemSummary'); getConfiguration(configurationItemSummary.resourceType, configurationItemSummary.resourceId, configurationItemSummary.configurationItemCaptureTime, (err, apiConfigurationItem) => { if (err) { callback(err); } const configurationItem = convertApiConfiguration(apiConfigurationItem); callback(null, configurationItem); }); } else { checkDefined(invokingEvent.configurationItem, 'configurationItem'); callback(null, invokingEvent.configurationItem); } } // Check whether the resource has been deleted. If the resource was deleted, then the evaluation returns not applicable. function isApplicable(configurationItem, event) { checkDefined(configurationItem, 'configurationItem'); checkDefined(event, 'event'); const status = configurationItem.configurationItemStatus; const eventLeftScope = event.eventLeftScope; return (status === 'OK' || status === 'ResourceDiscovered') && eventLeftScope === false; } // In this example, the resource is compliant if it is an instance and its type matches the type specified as the desired type. // If the resource is not an instance, then this resource is not applicable. function evaluateChangeNotificationCompliance(configurationItem, ruleParameters) { checkDefined(configurationItem, 'configurationItem'); checkDefined(configurationItem.configuration, 'configurationItem.configuration'); checkDefined(ruleParameters, 'ruleParameters'); if (configurationItem.resourceType !== 'AWS::EC2::Instance') { return 'NOT_APPLICABLE'; } else if (ruleParameters.desiredInstanceType === configurationItem.configuration.instanceType) { return 'COMPLIANT'; } return 'NON_COMPLIANT'; } // Receives the event and context from AWS Lambda. exports.handler = (event, context, callback) => { checkDefined(event, 'event'); const invokingEvent = JSON.parse(event.invokingEvent); const ruleParameters = JSON.parse(event.ruleParameters); getConfigurationItem(invokingEvent, (err, configurationItem) => { if (err) { callback(err); } let compliance = 'NOT_APPLICABLE'; const putEvaluationsRequest = {}; if (isApplicable(configurationItem, event)) { // Invoke the compliance checking function. compliance = evaluateChangeNotificationCompliance(configurationItem, ruleParameters); } // Initializes the request that contains the evaluation results. putEvaluationsRequest.Evaluations = [ { ComplianceResourceType: configurationItem.resourceType, ComplianceResourceId: configurationItem.resourceId, ComplianceType: compliance, OrderingTimestamp: configurationItem.configurationItemCaptureTime, }, ]; putEvaluationsRequest.ResultToken = event.resultToken; // Sends the evaluation results to AWS Config. config.putEvaluations(putEvaluationsRequest, (error, data) => { if (error) { callback(error, null); } else if (data.FailedEvaluations.length > 0) { // Ends the function if evaluation results are not successfully reported to AWS Config. callback(JSON.stringify(data), null); } else { callback(null, data); } }); }); };

Operaciones de funciones

La función realiza las siguientes operaciones en tiempo de ejecución:

  1. La función se ejecuta cuando AWS Lambda pasa el objeto event a la función handler. AWS Lambda también pasa un objeto context, que contiene información y métodos que la función puede utilizar mientras se ejecuta. En este ejemplo, la función acepta el parámetro callback opcional, que utiliza para devolver información al intermediario.

  2. La función comprueba si el messageType del evento es un elemento de configuración o un elemento de configuración sobredimensionado y, a continuación, devuelve el elemento de configuración.

  3. El controlador llama a la función isApplicable para determinar si el recurso se ha eliminado.

  4. El controlador llama a la función evaluateChangeNotificationCompliance y pasa los objetos configurationItem y ruleParameters que AWS Config ha publicado en el evento.

    La función evalúa primero si el recurso es una instancia EC2. Si el recurso no es una instancia EC2, la función devuelve un valor de conformidad de NOT_APPLICABLE.

    Luego, la función evalúa si el atributo instanceType del elemento de configuración es igual al valor del parámetro desiredInstanceType. Si los valores son iguales, la función devuelve COMPLIANT. Si los valores no son iguales, la función devuelve NON_COMPLIANT.

  5. El controlador se prepara para enviar los resultados de la evaluación a AWS Config inicializando el objeto putEvaluationsRequest. Este objeto incluye el parámetro Evaluations, que identifica el resultado de conformidad, el tipo de recurso y el ID del recurso que se ha evaluado. El objeto putEvaluationsRequest también incluye el token del resultado del evento, que identifica la regla y el evento para AWS Config.

  6. El controlador envía los resultados de la evaluación a AWS Config pasando el objeto al método putEvaluations del cliente config.

Función de ejemplo para evaluaciones periódicas

AWS Config invoca una función como la del siguiente ejemplo para evaluaciones periódicas. Las evaluaciones periódicas se producen con la frecuencia que especifique al definir la regla en AWS Config.

Si utiliza la consola de AWS Config para crear una regla que esté asociada a una función como la de este ejemplo, elija Periodic (Periódico) como tipo de disparador. Si utiliza la API de AWS Config o AWS CLI para crear la regla, establezca el atributo MessageType en ScheduledNotification.

En este ejemplo, se comprueba si el número total de un recurso especificado supera un máximo especificado.

var aws = require('aws-sdk'), // Loads the AWS SDK for JavaScript. config = new aws.ConfigService(), // Constructs a service object to use the aws.ConfigService class. COMPLIANCE_STATES = { COMPLIANT : 'COMPLIANT', NON_COMPLIANT : 'NON_COMPLIANT', NOT_APPLICABLE : 'NOT_APPLICABLE' }; // Receives the event and context from AWS Lambda. exports.handler = function(event, context, callback) { // Parses the invokingEvent and ruleParameters values, which contain JSON objects passed as strings. var invokingEvent = JSON.parse(event.invokingEvent), ruleParameters = JSON.parse(event.ruleParameters), noOfResources = 0; if (isScheduledNotification(invokingEvent)) { countResourceTypes(ruleParameters.applicableResourceType, "", noOfResources, function(err, count) { if (err === null) { var putEvaluationsRequest; // Initializes the request that contains the evaluation results. putEvaluationsRequest = { Evaluations : [ { // Applies the evaluation result to the AWS account published in the event. ComplianceResourceType : 'AWS::::Account', ComplianceResourceId : event.accountId, ComplianceType : evaluateCompliance(ruleParameters.maxCount, count), OrderingTimestamp : new Date() } ], ResultToken : event.resultToken }; // Sends the evaluation results to AWS Config. config.putEvaluations(putEvaluationsRequest, function(err, data) { if (err) { callback(err, null); } else { if (data.FailedEvaluations.length > 0) { // Ends the function execution if evaluation results are not successfully reported callback(JSON.stringify(data)); } callback(null, data); } }); } else { callback(err, null); } }); } else { console.log("Invoked for a notification other than Scheduled Notification... Ignoring."); } }; // Checks whether the invoking event is ScheduledNotification. function isScheduledNotification(invokingEvent) { return (invokingEvent.messageType === 'ScheduledNotification'); } // Checks whether the compliance conditions for the rule are violated. function evaluateCompliance(maxCount, actualCount) { if (actualCount > maxCount) { return COMPLIANCE_STATES.NON_COMPLIANT; } else { return COMPLIANCE_STATES.COMPLIANT; } } // Counts the applicable resources that belong to the AWS account. function countResourceTypes(applicableResourceType, nextToken, count, callback) { config.listDiscoveredResources({resourceType : applicableResourceType, nextToken : nextToken}, function(err, data) { if (err) { callback(err, null); } else { count = count + data.resourceIdentifiers.length; if (data.nextToken !== undefined && data.nextToken != null) { countResourceTypes(applicableResourceType, data.nextToken, count, callback); } callback(null, count); } }); return count; }

Operaciones de funciones

La función realiza las siguientes operaciones en tiempo de ejecución:

  1. La función se ejecuta cuando AWS Lambda pasa el objeto event a la función handler. AWS Lambda también pasa un objeto context, que contiene información y métodos que la función puede utilizar mientras se ejecuta. En este ejemplo, la función acepta el parámetro callback opcional, que utiliza para devolver información al intermediario.

  2. Para contar los recursos del tipo especificado, el controlador llama a la función countResourceTypes y pasa el parámetro applicableResourceType que ha recibido del evento. La función countResourceTypes llama al método listDiscoveredResources del cliente config, que devuelve una lista de identificadores para los recursos aplicables. La función utiliza la longitud de esta lista para determinar el número de recursos aplicables y devuelve este número al controlador.

  3. El controlador se prepara para enviar los resultados de la evaluación a AWS Config inicializando el objeto putEvaluationsRequest. Este objeto incluye el parámetro Evaluations, que identifica el resultado de conformidad y de la cuenta de AWS que se publicó en el evento. Puede utilizar el parámetro Evaluations para aplicar el resultado a cualquier tipo de recurso admitido por AWS Config. El objeto putEvaluationsRequest también incluye el token del resultado del evento, que identifica la regla y el evento para AWS Config.

  4. En el objeto putEvaluationsRequest, el controlador llama a la función evaluateCompliance. Esta función comprueba si el número de recursos aplicables supera el máximo asignado al parámetro maxCount, proporcionado anteriormente por el evento. Si el número de recursos supera el máximo, la función devuelve NON_COMPLIANT. Si el número de recursos no supera el máximo, la función devuelve COMPLIANT.

  5. El controlador envía los resultados de la evaluación a AWS Config pasando el objeto al método putEvaluations del cliente config.